diff --git a/.changeset/afraid-bananas-behave.md b/.changeset/afraid-bananas-behave.md deleted file mode 100644 index 624b798c17..0000000000 --- a/.changeset/afraid-bananas-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue where the `--successCache` option for the `repo test` and `repo lint` commands would be include the workspace path in generated cache keys. This previously broke caching in environments where the workspace path varies across builds. diff --git a/.changeset/afraid-carrots-greet.md b/.changeset/afraid-carrots-greet.md deleted file mode 100644 index 9f77cba9b8..0000000000 --- a/.changeset/afraid-carrots-greet.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -- Updated EntityLayout component to implement breadcrumb navigation based on the entity relations. - -- Added parentEntityRelations prop to EntityLayoutProps to specify relation types for parent entities. diff --git a/.changeset/angry-bags-compete.md b/.changeset/angry-bags-compete.md deleted file mode 100644 index 87e9bf36b8..0000000000 --- a/.changeset/angry-bags-compete.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': minor ---- - -Added support for pagination in api-docs plugin - DefaultApiExplorerPage diff --git a/.changeset/beige-chicken-type.md b/.changeset/beige-chicken-type.md new file mode 100644 index 0000000000..d73500a7f9 --- /dev/null +++ b/.changeset/beige-chicken-type.md @@ -0,0 +1,5 @@ +--- +'yarn-plugin-backstage': patch +--- + +Use yarn's built-in http utilities for fetching release manifests diff --git a/.changeset/big-tips-heal.md b/.changeset/big-tips-heal.md deleted file mode 100644 index a223cda256..0000000000 --- a/.changeset/big-tips-heal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': minor ---- - -Internal update to use the updated generated code from `backstage-cli package schema openapi generate --client-package ...`. diff --git a/.changeset/blue-dragons-shout.md b/.changeset/blue-dragons-shout.md new file mode 100644 index 0000000000..762234a72b --- /dev/null +++ b/.changeset/blue-dragons-shout.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +`restrictUsersToGroup` should use the entire group path when getting members diff --git a/.changeset/brave-maps-deliver.md b/.changeset/brave-maps-deliver.md new file mode 100644 index 0000000000..51b60af153 --- /dev/null +++ b/.changeset/brave-maps-deliver.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Updated Dockerfile to include `backstage.json` file diff --git a/.changeset/brave-teachers-mate.md b/.changeset/brave-teachers-mate.md new file mode 100644 index 0000000000..22f768b441 --- /dev/null +++ b/.changeset/brave-teachers-mate.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/backend-defaults': patch +'@backstage/plugin-catalog-backend': patch +--- + +Updated dependency `@opentelemetry/api` to `^1.9.0`. diff --git a/.changeset/bright-boats-dream.md b/.changeset/bright-boats-dream.md new file mode 100644 index 0000000000..580a334a93 --- /dev/null +++ b/.changeset/bright-boats-dream.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Immediately close all connections when shutting down in local development. diff --git a/.changeset/bright-buckets-laugh.md b/.changeset/bright-buckets-laugh.md deleted file mode 100644 index e1e610b72a..0000000000 --- a/.changeset/bright-buckets-laugh.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix dev server reloads of plugin discovery for new frontend system. diff --git a/.changeset/bright-singers-do.md b/.changeset/bright-singers-do.md deleted file mode 100644 index 8b10363612..0000000000 --- a/.changeset/bright-singers-do.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': minor ---- - -**BREAKING** The `dynamicPluginsFeatureLoader` options related to the root logger behavior (`transports`, `level`, `format`) are now gathered under a single `logger` option which is a function taking an optional `Config` argument and returning the logger options. - -This breaking change is required for 2 reasons: - -- it's totally possible that the current `Config` would be required to provide the logger options, -- the logger-related options should be gathered under a common `logger` option because, when the root auditing service is introduced, distinct but similarly-named options would be required for the auditor as well. diff --git a/.changeset/brown-monkeys-ring.md b/.changeset/brown-monkeys-ring.md new file mode 100644 index 0000000000..5aaf738d38 --- /dev/null +++ b/.changeset/brown-monkeys-ring.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +If the Backstage yarn plugin is installed, it will now be automatically updated as part of `versions:bump`. diff --git a/.changeset/chatty-files-sniff.md b/.changeset/chatty-files-sniff.md new file mode 100644 index 0000000000..11eebbb93b --- /dev/null +++ b/.changeset/chatty-files-sniff.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +adding requiredLinearHistory property for branch protection settings diff --git a/.changeset/chatty-weeks-impress.md b/.changeset/chatty-weeks-impress.md new file mode 100644 index 0000000000..21beb168e9 --- /dev/null +++ b/.changeset/chatty-weeks-impress.md @@ -0,0 +1,44 @@ +--- +'@backstage/plugin-home': patch +--- + +Added a new Quick Start Card to `plugin-home`, which can display basic info to get users the info they need to onboard to the Catalog. + +``` +import { QuickStartCard } from '@backstage/plugin-home'; + + } + cardDescription="Backstage system model will help you create new entities" + video={ + + } + downloadImage={ + + } +/> +``` + +See the [storybook examples](https://backstage.io/storybook/?path=/story/plugins-home-components-quickstartcard--default) diff --git a/.changeset/chilled-taxis-dance.md b/.changeset/chilled-taxis-dance.md deleted file mode 100644 index e2a5dcecee..0000000000 --- a/.changeset/chilled-taxis-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The check for `react-dom/client` in the Jest configuration will now properly always run from the target directory. diff --git a/.changeset/chilly-games-trade.md b/.changeset/chilly-games-trade.md new file mode 100644 index 0000000000..259063776f --- /dev/null +++ b/.changeset/chilly-games-trade.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-defaults': minor +--- + +Added a new `backend.health.headers` configuration that can be used to set additional headers to include in health check responses. + +**BREAKING CONSUMERS**: As part of this change the `createHealthRouter` function exported from `@backstage/backend-defaults/rootHttpRouter` now requires the root config service to be passed through the `config` option. diff --git a/.changeset/cold-icons-worry.md b/.changeset/cold-icons-worry.md new file mode 100644 index 0000000000..4e0b461b24 --- /dev/null +++ b/.changeset/cold-icons-worry.md @@ -0,0 +1,6 @@ +--- +'@backstage/cli': patch +--- + +Remove special-casing for `@types` packages when generating dependency entries +during templating diff --git a/.changeset/cold-jeans-stare.md b/.changeset/cold-jeans-stare.md new file mode 100644 index 0000000000..c0356db3ad --- /dev/null +++ b/.changeset/cold-jeans-stare.md @@ -0,0 +1,5 @@ +--- +'@backstage/create-app': patch +--- + +Updated the template to use `@backstage/cli/config/prettier` instead of `@spotify/prettier-config`. diff --git a/.changeset/cool-days-sparkle.md b/.changeset/cool-days-sparkle.md new file mode 100644 index 0000000000..1dc9a76df7 --- /dev/null +++ b/.changeset/cool-days-sparkle.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-backend-module-bitbucket-server': minor +'@backstage/backend-defaults': minor +--- + +Throttles Bitbucket Server API calls diff --git a/.changeset/create-app-1729608704.md b/.changeset/create-app-1729608704.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1729608704.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/create-app-1730809984.md b/.changeset/create-app-1730809984.md deleted file mode 100644 index b50d431d4b..0000000000 --- a/.changeset/create-app-1730809984.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Bumped create-app version. diff --git a/.changeset/cuddly-chicken-wink.md b/.changeset/cuddly-chicken-wink.md new file mode 100644 index 0000000000..79843ba64d --- /dev/null +++ b/.changeset/cuddly-chicken-wink.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Export `PluginTokenHandler` and `pluginTokenHandlerDecoratorServiceRef` to allow for custom decoration of the plugin token handler without having to re-implement the entire handler. diff --git a/.changeset/cuddly-schools-scream.md b/.changeset/cuddly-schools-scream.md new file mode 100644 index 0000000000..533d3d1d4e --- /dev/null +++ b/.changeset/cuddly-schools-scream.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-github': patch +--- + +Pass in a default schedule to the `GithubEntityProvider` if none is provided diff --git a/.changeset/curly-beans-brake.md b/.changeset/curly-beans-brake.md new file mode 100644 index 0000000000..4afb11578d --- /dev/null +++ b/.changeset/curly-beans-brake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': minor +--- + +Add pagination support to TechDocs Index Page and make it the default diff --git a/.changeset/curly-hats-tell.md b/.changeset/curly-hats-tell.md new file mode 100644 index 0000000000..c0e061c99b --- /dev/null +++ b/.changeset/curly-hats-tell.md @@ -0,0 +1,18 @@ +--- +'@backstage/backend-defaults': minor +'@backstage/backend-test-utils': minor +--- + +**BREAKING** Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys. + +This is a breaking change for clients using the `redis` store for cache with `useRedisSets` option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore. + +If you were using `useRedisSets` option in configuration make sure to remove it from `app-config.yaml`: + +```diff +backend: + cache: + store: redis + connection: redis://user:pass@cache.example.com:6379 +- useRedisSets: false +``` diff --git a/.changeset/curly-teachers-marry.md b/.changeset/curly-teachers-marry.md new file mode 100644 index 0000000000..9bf771f4d1 --- /dev/null +++ b/.changeset/curly-teachers-marry.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Added a new `catalog.disableRelationsCompatibility` configuration option that avoids JSON deserialization and serialization if possible when reading entities. This significantly reduces the memory usage of the catalog, and slightly increases performance, but it removes the backwards compatibility processing that ensures that both `entity.relation[].target` and `entity.relation[].targetRef` are present in returned entities. diff --git a/.changeset/curvy-bears-nail.md b/.changeset/curvy-bears-nail.md deleted file mode 100644 index d0bdd51401..0000000000 --- a/.changeset/curvy-bears-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/theme': patch ---- - -Internal refactor to avoid top-level imports from MUI. diff --git a/.changeset/curvy-fishes-rule.md b/.changeset/curvy-fishes-rule.md new file mode 100644 index 0000000000..2ce535166d --- /dev/null +++ b/.changeset/curvy-fishes-rule.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Fix server response time by moving the lifecycle startup hooks back to the plugin lifecycle service. diff --git a/.changeset/curvy-poems-joke.md b/.changeset/curvy-poems-joke.md deleted file mode 100644 index 9b8ea5998b..0000000000 --- a/.changeset/curvy-poems-joke.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': patch ---- - -Fixed an issue causing the `CatalogIndexPage` to not properly filter results when using offset pagination. diff --git a/.changeset/cyan-rocks-divide.md b/.changeset/cyan-rocks-divide.md new file mode 100644 index 0000000000..8576e515d8 --- /dev/null +++ b/.changeset/cyan-rocks-divide.md @@ -0,0 +1,5 @@ +--- +'@backstage/integration': minor +--- + +Add the integration for Azure blob storage to read the credentials to access the storage account and provide the default credential provider. diff --git a/.changeset/cyan-trees-bow.md b/.changeset/cyan-trees-bow.md deleted file mode 100644 index 6f23f67f55..0000000000 --- a/.changeset/cyan-trees-bow.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-events-node': patch ---- - -Fixed an issue where subscribing to events threw an error and gave up too easily. Calling the subscribe method will cause the background polling loop to keep trying to connect to the events backend, even if the initial request fails. - -By default the events service will attempt to publish and subscribe to events from the events bus API in the events backend, but if it fails due to the events backend not being installed, it will bail and never try calling the API again. There is now a new `events.useEventBus` configuration and option for the `DefaultEventsService` that lets you control this behavior. You can set it to `'never'` to disabled API calls to the events backend completely, or `'always'` to never allow it to be disabled. diff --git a/.changeset/dry-badgers-prove.md b/.changeset/dry-badgers-prove.md new file mode 100644 index 0000000000..efd2011a7b --- /dev/null +++ b/.changeset/dry-badgers-prove.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Perform the by-query count inlined with the main query diff --git a/.changeset/dry-needles-taste.md b/.changeset/dry-needles-taste.md new file mode 100644 index 0000000000..472bc0edb3 --- /dev/null +++ b/.changeset/dry-needles-taste.md @@ -0,0 +1,6 @@ +--- +'@backstage/core-app-api': patch +'@backstage/plugin-app': patch +--- + +The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes. diff --git a/.changeset/dull-bulldogs-learn.md b/.changeset/dull-bulldogs-learn.md new file mode 100644 index 0000000000..0892ecb6ba --- /dev/null +++ b/.changeset/dull-bulldogs-learn.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +The user and plugin token verification in the default `AuthService` implementation will no longer forward verification errors to the caller, and instead log them as warnings. diff --git a/.changeset/dull-ties-film.md b/.changeset/dull-ties-film.md new file mode 100644 index 0000000000..4463d59d91 --- /dev/null +++ b/.changeset/dull-ties-film.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Adds an optional columns attribute to HasSubdomainsCardProps and changes its default columns diff --git a/.changeset/early-cobras-compare.md b/.changeset/early-cobras-compare.md deleted file mode 100644 index 591d1377f3..0000000000 --- a/.changeset/early-cobras-compare.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-ldap': patch ---- - -Added a `dnCaseSensitive` flag to support LDAP servers with mixed-case attributes. diff --git a/.changeset/early-monkeys-hammer.md b/.changeset/early-monkeys-hammer.md deleted file mode 100644 index fab689d517..0000000000 --- a/.changeset/early-monkeys-hammer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -bump `@asyncapi/react-component` to latest `2.x` diff --git a/.changeset/empty-bugs-deliver.md b/.changeset/empty-bugs-deliver.md new file mode 100644 index 0000000000..5b26f4eaca --- /dev/null +++ b/.changeset/empty-bugs-deliver.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Export `DefaultHttpAuthService` to allow for custom token extraction logic. diff --git a/.changeset/empty-colts-promise.md b/.changeset/empty-colts-promise.md new file mode 100644 index 0000000000..80cea4d42e --- /dev/null +++ b/.changeset/empty-colts-promise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Internal refactor of filter parsing logic. diff --git a/.changeset/empty-lobsters-wait.md b/.changeset/empty-lobsters-wait.md deleted file mode 100644 index 404b0c8066..0000000000 --- a/.changeset/empty-lobsters-wait.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': minor ---- - -Use `HumanDuration` for all duration needs in the public API, instead of `luxon` types. These are generally compatible, with a few caveats: - -- If you scheduled things to run quarterly (`quarter` or `quarters`), you can use `{ months: 3 }` instead. -- If you used the singular nouns such as `year: 1`, use plurals instead (e.g. `years: 1`). diff --git a/.changeset/empty-ways-push.md b/.changeset/empty-ways-push.md new file mode 100644 index 0000000000..11a67985d8 --- /dev/null +++ b/.changeset/empty-ways-push.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-module-elasticsearch': patch +--- + +Update the ElasticSearchSearchEngine translator to handle phrase searches. diff --git a/.changeset/fast-cheetahs-deliver.md b/.changeset/fast-cheetahs-deliver.md new file mode 100644 index 0000000000..ce87a68409 --- /dev/null +++ b/.changeset/fast-cheetahs-deliver.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Deprecate old-backend-system `IncrementalCatalogBuilder` diff --git a/.changeset/fast-tools-fix.md b/.changeset/fast-tools-fix.md new file mode 100644 index 0000000000..11807f045e --- /dev/null +++ b/.changeset/fast-tools-fix.md @@ -0,0 +1,10 @@ +--- +'@backstage/backend-defaults': minor +--- + +**BREAKING PRODUCERS**: The `LifecycleMiddlewareOptions.startupRequestPauseTimeout` has been removed. Use the `backend.lifecycle.startupRequestPauseTimeout` setting in your `app-config.yaml` file to customize how the `createLifecycleMiddleware` function should behave. Also the root config service is required as an option when calling the `createLifecycleMiddleware` function: + +```diff +- createLifecycleMiddleware({ lifecycle, startupRequestPauseTimeout }) ++ createLifecycleMiddleware({ config, lifecycle }) +``` diff --git a/.changeset/few-colts-train.md b/.changeset/few-colts-train.md new file mode 100644 index 0000000000..1dc6becad1 --- /dev/null +++ b/.changeset/few-colts-train.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-ldap': minor +--- + +Updated fix for ldap entity mapping which doesn't require extra config setting of dnCaseSensitive diff --git a/.changeset/few-hornets-rush.md b/.changeset/few-hornets-rush.md deleted file mode 100644 index 7d23a5ffc9..0000000000 --- a/.changeset/few-hornets-rush.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-google-provider': patch ---- - -Fix visibility of config for use in front end code diff --git a/.changeset/few-lizards-search.md b/.changeset/few-lizards-search.md deleted file mode 100644 index 12102c7282..0000000000 --- a/.changeset/few-lizards-search.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/types': minor ---- - -Introduce `createDeferred` and `DeferredPromise`. diff --git a/.changeset/few-pillows-remember.md b/.changeset/few-pillows-remember.md new file mode 100644 index 0000000000..8f13651a70 --- /dev/null +++ b/.changeset/few-pillows-remember.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fixed an issue causing the `EntityOwnerPicker` to reset scrolling when more elements are loaded. diff --git a/.changeset/fifty-countries-decide.md b/.changeset/fifty-countries-decide.md new file mode 100644 index 0000000000..9c4553f3be --- /dev/null +++ b/.changeset/fifty-countries-decide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Implement `/entities` in terms of `queryEntities` to not run into memory and performance problems on large catalogs diff --git a/.changeset/five-goats-travel.md b/.changeset/five-goats-travel.md new file mode 100644 index 0000000000..361c530fca --- /dev/null +++ b/.changeset/five-goats-travel.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': patch +--- + +Log request and response metadata so it can be used for filtering log messages. +The format of the request date was also changed from `clf` to `utc`. diff --git a/.changeset/flat-feet-do.md b/.changeset/flat-feet-do.md deleted file mode 100644 index 0495390273..0000000000 --- a/.changeset/flat-feet-do.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Updated engines to support Node 20 or 22 diff --git a/.changeset/fluffy-cobras-sort.md b/.changeset/fluffy-cobras-sort.md new file mode 100644 index 0000000000..363281a6c5 --- /dev/null +++ b/.changeset/fluffy-cobras-sort.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': minor +--- + +Implemented `AzureBlobStorageUrlReader` to read from the url of committed location from the entity provider diff --git a/.changeset/fluffy-falcons-shout.md b/.changeset/fluffy-falcons-shout.md new file mode 100644 index 0000000000..7cdce8229c --- /dev/null +++ b/.changeset/fluffy-falcons-shout.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-auth-backend': patch +'@backstage/plugin-auth-node': patch +--- + +Improved error forwarding for OAuth refresh endpoints diff --git a/.changeset/fluffy-zebras-cheer.md b/.changeset/fluffy-zebras-cheer.md new file mode 100644 index 0000000000..308f12d10a --- /dev/null +++ b/.changeset/fluffy-zebras-cheer.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +'@backstage/plugin-scaffolder-common': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks diff --git a/.changeset/forty-apples-complain.md b/.changeset/forty-apples-complain.md new file mode 100644 index 0000000000..5aa177a63f --- /dev/null +++ b/.changeset/forty-apples-complain.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-app-api': patch +--- + +Removed unused `express` dependencies. diff --git a/.changeset/forty-pets-wave.md b/.changeset/forty-pets-wave.md deleted file mode 100644 index 1b96867e7d..0000000000 --- a/.changeset/forty-pets-wave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-catalog': patch ---- - -Fixed a bug where the `filter` setting of the collator was not permitted to be an array. diff --git a/.changeset/forty-ravens-fry.md b/.changeset/forty-ravens-fry.md new file mode 100644 index 0000000000..8deb149441 --- /dev/null +++ b/.changeset/forty-ravens-fry.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +The default `authServiceFactory` now correctly depends on the plugin scoped `Logger` services rather than the root scoped one. diff --git a/.changeset/fresh-jeans-relate.md b/.changeset/fresh-jeans-relate.md deleted file mode 100644 index a8f6ad8e0b..0000000000 --- a/.changeset/fresh-jeans-relate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': minor ---- - -**BREAKING**: Updates ESLint config to ignore all generated source code under `src/**/generated/**/*.ts`. diff --git a/.changeset/friendly-dots-thank.md b/.changeset/friendly-dots-thank.md new file mode 100644 index 0000000000..50337c0a0f --- /dev/null +++ b/.changeset/friendly-dots-thank.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-search-backend-module-techdocs': patch +'@backstage/plugin-search-backend-module-catalog': patch +'@backstage/plugin-search-backend-module-explore': patch +--- + +Update README diff --git a/.changeset/friendly-hats-push.md b/.changeset/friendly-hats-push.md deleted file mode 100644 index e730fcbf8c..0000000000 --- a/.changeset/friendly-hats-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/integration-aws-node': patch ---- - -The `getDefaultCredentialsChain` function now accepts and applies a `region` parameter, preventing it from defaulting to `us-east-1` when no region is specified. diff --git a/.changeset/friendly-kids-judge.md b/.changeset/friendly-kids-judge.md deleted file mode 100644 index e4809c1f40..0000000000 --- a/.changeset/friendly-kids-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search': patch ---- - -Removes the card UI from the search results type filter for a cleaner UI consistent with other filters diff --git a/.changeset/friendly-melons-shake.md b/.changeset/friendly-melons-shake.md deleted file mode 100644 index 7bdbb58fea..0000000000 --- a/.changeset/friendly-melons-shake.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': patch ---- - -Enhance the `CommonJSModuleLoader` to add support for `resolvePackagePath` calls from backend dynamic plugins, with customizable package resolution, and make the `CommonJSModuleLoader` public API. -Fixing this backend dynamic plugin limitation related to `resolvePackagePath` is important for backend dynamic plugins which use the database, since database migration scripts systematically use `resolvePackagePath`. diff --git a/.changeset/funny-lemons-camp.md b/.changeset/funny-lemons-camp.md new file mode 100644 index 0000000000..1cb99ff2ba --- /dev/null +++ b/.changeset/funny-lemons-camp.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +Add a `toString` on the default `BackendFeatureMeta` implementations diff --git a/.changeset/gold-crabs-agree.md b/.changeset/gold-crabs-agree.md new file mode 100644 index 0000000000..1f345a8c10 --- /dev/null +++ b/.changeset/gold-crabs-agree.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Use a faster count method on pg when computing some metrics diff --git a/.changeset/gold-stingrays-cross.md b/.changeset/gold-stingrays-cross.md new file mode 100644 index 0000000000..f2a8da99b3 --- /dev/null +++ b/.changeset/gold-stingrays-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Fix a bug where sometimes the `by-query` endpoint could return nulls for entities that were not yet stitched. diff --git a/.changeset/good-pens-dance.md b/.changeset/good-pens-dance.md new file mode 100644 index 0000000000..05ebce1bc6 --- /dev/null +++ b/.changeset/good-pens-dance.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-react': patch +'@backstage/plugin-config-schema': patch +--- + +Internal refactor to break potential circular imports diff --git a/.changeset/gorgeous-panthers-count.md b/.changeset/gorgeous-panthers-count.md new file mode 100644 index 0000000000..f6c05d743b --- /dev/null +++ b/.changeset/gorgeous-panthers-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +The --no-node-snapshot check needs to be done against process.execArgv instead of process.argv diff --git a/.changeset/great-buttons-cross.md b/.changeset/great-buttons-cross.md new file mode 100644 index 0000000000..02247b94bf --- /dev/null +++ b/.changeset/great-buttons-cross.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app-backend': patch +--- + +Fixed a bug where config would not be injected on the `/` and `/index.html` paths. diff --git a/.changeset/green-carpets-smell.md b/.changeset/green-carpets-smell.md new file mode 100644 index 0000000000..0cda68de22 --- /dev/null +++ b/.changeset/green-carpets-smell.md @@ -0,0 +1,7 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +The `RootLifecycleService` now has a new `addBeforeShutdownHook` method, and hooks added through this method will run immediately when a termination event is received. + +The backend will not proceed with the shutdown and run the `Shutdown` hooks until all `BeforeShutdown` hooks have completed. diff --git a/.changeset/green-tools-arrive.md b/.changeset/green-tools-arrive.md deleted file mode 100644 index 78eed180d4..0000000000 --- a/.changeset/green-tools-arrive.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Fix issue with form state not refreshing when updating diff --git a/.changeset/grumpy-shoes-return.md b/.changeset/grumpy-shoes-return.md deleted file mode 100644 index e5bf70c0a5..0000000000 --- a/.changeset/grumpy-shoes-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue with the `--successCache` flag for `repo test` where the tree hash for the wrong package directory would sometimes be used to generate the cache key. diff --git a/.changeset/happy-forks-listen.md b/.changeset/happy-forks-listen.md new file mode 100644 index 0000000000..4274c830f1 --- /dev/null +++ b/.changeset/happy-forks-listen.md @@ -0,0 +1,5 @@ +--- +'@backstage/release-manifests': patch +--- + +Switch to native fetch for loading release manifests diff --git a/.changeset/healthy-bags-jog.md b/.changeset/healthy-bags-jog.md deleted file mode 100644 index ab4930963c..0000000000 --- a/.changeset/healthy-bags-jog.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-react': patch ---- - -add the pod delete feature to the kubernetes react plugin diff --git a/.changeset/healthy-lions-judge.md b/.changeset/healthy-lions-judge.md deleted file mode 100644 index f9ead85d2e..0000000000 --- a/.changeset/healthy-lions-judge.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-aws-alb-provider': minor -'@backstage/plugin-auth-backend': minor ---- - -**BREAKING**: The AWS ALB `fullProfile` will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result. diff --git a/.changeset/healthy-tables-wonder.md b/.changeset/healthy-tables-wonder.md deleted file mode 100644 index be6da63de0..0000000000 --- a/.changeset/healthy-tables-wonder.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor -'@backstage/plugin-search-backend': minor ---- - -Internal update to use the new generated server types from `backstage-cli package schema openapi generate --server`. diff --git a/.changeset/healthy-years-begin.md b/.changeset/healthy-years-begin.md new file mode 100644 index 0000000000..a1952b6648 --- /dev/null +++ b/.changeset/healthy-years-begin.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-search-react': patch +'@backstage/plugin-search': patch +--- + +Use Select from core-components and update Lifecycle filter to use Select instead checkboxes. diff --git a/.changeset/heavy-mice-raise.md b/.changeset/heavy-mice-raise.md deleted file mode 100644 index 8b32ecb4d7..0000000000 --- a/.changeset/heavy-mice-raise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': patch ---- - -Fix issue with `Stepper` and trying to trim additional properties. This is now all behind `liveOmit` and `omitExtraData` instead. diff --git a/.changeset/heavy-needles-poke.md b/.changeset/heavy-needles-poke.md new file mode 100644 index 0000000000..91a98a9102 --- /dev/null +++ b/.changeset/heavy-needles-poke.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-defaults': patch +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. diff --git a/.changeset/heavy-tomatoes-laugh.md b/.changeset/heavy-tomatoes-laugh.md new file mode 100644 index 0000000000..9a4740e209 --- /dev/null +++ b/.changeset/heavy-tomatoes-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': minor +--- + +Service factories added by feature loaders now have lower priority and will be ignored if a factory for the same service is added directly by `backend.add(serviceFactory)`. diff --git a/.changeset/honest-buttons-clean.md b/.changeset/honest-buttons-clean.md new file mode 100644 index 0000000000..952aff614b --- /dev/null +++ b/.changeset/honest-buttons-clean.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Revert `css-loader@v7` bump diff --git a/.changeset/honest-hornets-double.md b/.changeset/honest-hornets-double.md new file mode 100644 index 0000000000..6c2bffa5af --- /dev/null +++ b/.changeset/honest-hornets-double.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-node': minor +--- + +Updated the `catalogServiceMock` return type to match both `CatalogService` and `CatalogApi` diff --git a/.changeset/hungry-cats-juggle.md b/.changeset/hungry-cats-juggle.md deleted file mode 100644 index af52f9388f..0000000000 --- a/.changeset/hungry-cats-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix an issue with index page of documentation site being re-rendered. diff --git a/.changeset/hungry-hairs-wait.md b/.changeset/hungry-hairs-wait.md new file mode 100644 index 0000000000..ed4cd01ac7 --- /dev/null +++ b/.changeset/hungry-hairs-wait.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +Generated OpenAPI clients now support paths with tags. diff --git a/.changeset/hungry-owls-sell.md b/.changeset/hungry-owls-sell.md deleted file mode 100644 index cb2c18c21c..0000000000 --- a/.changeset/hungry-owls-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Fix techdocs config schema for custom elements sanitizer diff --git a/.changeset/itchy-elephants-trade.md b/.changeset/itchy-elephants-trade.md deleted file mode 100644 index 8ac6aaeeb9..0000000000 --- a/.changeset/itchy-elephants-trade.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-events-backend': patch -'@backstage/plugin-events-node': patch ---- - -Fix `events.useEventBus` by propagating config to `DefaultEventsService` diff --git a/.changeset/itchy-rats-pump.md b/.changeset/itchy-rats-pump.md new file mode 100644 index 0000000000..3b9073da77 --- /dev/null +++ b/.changeset/itchy-rats-pump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Compute deltas more efficiently, which generally leads to less wasted processing cycles diff --git a/.changeset/itchy-ravens-punch.md b/.changeset/itchy-ravens-punch.md new file mode 100644 index 0000000000..7d4cb9cd92 --- /dev/null +++ b/.changeset/itchy-ravens-punch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Implement `/entities/by-name/:kind/:namespace/:name` using `getEntitiesByRefs` diff --git a/.changeset/khaki-badgers-watch.md b/.changeset/khaki-badgers-watch.md deleted file mode 100644 index 50458cc63e..0000000000 --- a/.changeset/khaki-badgers-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Improve error messages from Gitlab diff --git a/.changeset/khaki-fireants-march.md b/.changeset/khaki-fireants-march.md deleted file mode 100644 index ec84fe1b63..0000000000 --- a/.changeset/khaki-fireants-march.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added `--alwaysPack` as a replacement for the now hidden `--alwaysYarnPack` flag for the `build-workspace` command. diff --git a/.changeset/khaki-ladybugs-swim.md b/.changeset/khaki-ladybugs-swim.md new file mode 100644 index 0000000000..79cc1358df --- /dev/null +++ b/.changeset/khaki-ladybugs-swim.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-events-node': patch +--- + +Clarified purpose of subscriber ID in TSDoc for `EventsServiceSubscribeOptions`. diff --git a/.changeset/khaki-pugs-perform.md b/.changeset/khaki-pugs-perform.md deleted file mode 100644 index 55f89336ed..0000000000 --- a/.changeset/khaki-pugs-perform.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -Added title to the Notifications' table. The title clearly states the filter selection and total count of messages. This change aligns the look and feel closer to other tables. diff --git a/.changeset/khaki-shrimps-tease.md b/.changeset/khaki-shrimps-tease.md new file mode 100644 index 0000000000..a4dd3bc8e0 --- /dev/null +++ b/.changeset/khaki-shrimps-tease.md @@ -0,0 +1,9 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': minor +'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder-node': patch +'@backstage/plugin-scaffolder': patch +--- + +Added the autocomplete feature to GitlabRepoUrlPicker diff --git a/.changeset/kind-steaks-flow.md b/.changeset/kind-steaks-flow.md deleted file mode 100644 index fc93d5b1d0..0000000000 --- a/.changeset/kind-steaks-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -The "Created after" filter renamed to the "Sent out" based on the received users' feedback. diff --git a/.changeset/large-birds-watch.md b/.changeset/large-birds-watch.md new file mode 100644 index 0000000000..24d63492bc --- /dev/null +++ b/.changeset/large-birds-watch.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Mock the new `RootLifecycleService.addBeforeShutdownHook` method. diff --git a/.changeset/late-kings-wave.md b/.changeset/late-kings-wave.md deleted file mode 100644 index 01877f2732..0000000000 --- a/.changeset/late-kings-wave.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added a new `"rejectFrontendNetworkRequests"` configuration flag that can be set in the `"jest"` field in the root `package.json`: - -```json -{ - "jest": { - "rejectFrontendNetworkRequests": true - } -} -``` - -This flag causes rejection of any form of network requests that are attempted to be made in frontend or common package tests. This flag can only be set in the root `package.json` and can not be overridden in individual package configurations. diff --git a/.changeset/lazy-pants-attack.md b/.changeset/lazy-pants-attack.md new file mode 100644 index 0000000000..87a5fadb45 --- /dev/null +++ b/.changeset/lazy-pants-attack.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Fix issue with `jwks` endpoint returning invalid data with `firestore` diff --git a/.changeset/lazy-years-float.md b/.changeset/lazy-years-float.md new file mode 100644 index 0000000000..23bd77a0bb --- /dev/null +++ b/.changeset/lazy-years-float.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fix catalog filtering to allow searching entities by display name diff --git a/.changeset/lemon-bulldogs-study.md b/.changeset/lemon-bulldogs-study.md new file mode 100644 index 0000000000..7bb15b8193 --- /dev/null +++ b/.changeset/lemon-bulldogs-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog': minor +--- + +Consistent title behaviour across CatalogTable, CursorPaginatedCatalogTable, and OffsetPaginatedCatalogTable. diff --git a/.changeset/lemon-gifts-crash.md b/.changeset/lemon-gifts-crash.md deleted file mode 100644 index c4ab159dc8..0000000000 --- a/.changeset/lemon-gifts-crash.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-scaffolder-common': patch -'@backstage/plugin-scaffolder-react': patch -'@backstage/plugin-scaffolder': minor ---- - -Add scaffolder permission `scaffolder.template.management` for accessing the template management features diff --git a/.changeset/little-rivers-deny.md b/.changeset/little-rivers-deny.md deleted file mode 100644 index 8a6c60311e..0000000000 --- a/.changeset/little-rivers-deny.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': minor ---- - -Made it possible to construct `mockServices.database` with a given knex instance diff --git a/.changeset/long-geese-report.md b/.changeset/long-geese-report.md new file mode 100644 index 0000000000..1e638703c9 --- /dev/null +++ b/.changeset/long-geese-report.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Change `github:environment:create` action to request and use a token when resolving reviewer entity refs from the Backstage catalog. diff --git a/.changeset/loud-plants-dream.md b/.changeset/loud-plants-dream.md deleted file mode 100644 index a5099a088d..0000000000 --- a/.changeset/loud-plants-dream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Add `--max-warnings -1` support to `backstage-cli package lint` diff --git a/.changeset/loud-trainers-yawn.md b/.changeset/loud-trainers-yawn.md deleted file mode 100644 index b48f773caa..0000000000 --- a/.changeset/loud-trainers-yawn.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -The `--successCache` option for the `repo test` and `repo lint` commands now use an additive store that keeps old entries around for a week before they are cleaned up automatically. diff --git a/.changeset/lucky-bananas-eat.md b/.changeset/lucky-bananas-eat.md deleted file mode 100644 index 758ff95c36..0000000000 --- a/.changeset/lucky-bananas-eat.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-import': patch ---- - -Fixed parsing of catalog-info.yaml when creating a PR to register a repository if the file contains more than one document diff --git a/.changeset/lucky-crabs-vanish.md b/.changeset/lucky-crabs-vanish.md new file mode 100644 index 0000000000..158200fb7e --- /dev/null +++ b/.changeset/lucky-crabs-vanish.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +'@backstage/plugin-scaffolder-backend': patch +'@backstage/create-app': patch +--- + +Add github backend module to create-app and improve error messages diff --git a/.changeset/lucky-snakes-complain.md b/.changeset/lucky-snakes-complain.md deleted file mode 100644 index 83aca565ba..0000000000 --- a/.changeset/lucky-snakes-complain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Change core component Table tool bar search box to the a appropriate Search icon and text diff --git a/.changeset/mean-shirts-design.md b/.changeset/mean-shirts-design.md new file mode 100644 index 0000000000..ea89c6ecfd --- /dev/null +++ b/.changeset/mean-shirts-design.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +add PackageManager and Lockfile interfaces for future use diff --git a/.changeset/mean-years-deliver.md b/.changeset/mean-years-deliver.md deleted file mode 100644 index 82b4a12688..0000000000 --- a/.changeset/mean-years-deliver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Fix issue with token not being available because it's now non-enumerable diff --git a/.changeset/metal-files-itch.md b/.changeset/metal-files-itch.md deleted file mode 100644 index ac045eba9f..0000000000 --- a/.changeset/metal-files-itch.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/cli': minor ---- - -Added a new optimization to the `repo test` command that will filter out unused packages in watch mode if all provide filters are paths that point from the repo root. This significantly speeds up running individual tests from the repo root in a large workspace, for example: - -```sh -yarn test packages/app/src/App.test.tsx -``` diff --git a/.changeset/mighty-birds-rest.md b/.changeset/mighty-birds-rest.md new file mode 100644 index 0000000000..79f1bdd075 --- /dev/null +++ b/.changeset/mighty-birds-rest.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications': minor +--- + +Switched to using the new `/notifications` endpoints. Be sure to update the `notifications` plugin backend before deploying this frontend plugin change. diff --git a/.changeset/mighty-jobs-unite.md b/.changeset/mighty-jobs-unite.md deleted file mode 100644 index c8e880ba3e..0000000000 --- a/.changeset/mighty-jobs-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-api-docs': patch ---- - -Uses theme values to style the API definition schema so that theme overrides apply. diff --git a/.changeset/mighty-spoons-suffer.md b/.changeset/mighty-spoons-suffer.md deleted file mode 100644 index 5b03378568..0000000000 --- a/.changeset/mighty-spoons-suffer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Avoid page re-rendering when clicking on anchor links in the same documentation page. diff --git a/.changeset/moody-chicken-enjoy.md b/.changeset/moody-chicken-enjoy.md deleted file mode 100644 index 54919557f3..0000000000 --- a/.changeset/moody-chicken-enjoy.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/config-loader': patch ---- - -Internal refactor to use the deferred from the types package diff --git a/.changeset/neat-buttons-wait.md b/.changeset/neat-buttons-wait.md deleted file mode 100644 index 047f2e90c7..0000000000 --- a/.changeset/neat-buttons-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Ensure EntityDisplayName component link receives underline on hover. diff --git a/.changeset/neat-insects-cough.md b/.changeset/neat-insects-cough.md new file mode 100644 index 0000000000..fbdf214edb --- /dev/null +++ b/.changeset/neat-insects-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Be more aggressive in dequeueing entities for stitching diff --git a/.changeset/new-pandas-perform.md b/.changeset/new-pandas-perform.md new file mode 100644 index 0000000000..797f34d6df --- /dev/null +++ b/.changeset/new-pandas-perform.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': minor +--- + +Fix invalid path and malformed flags bugs in api-reports.ts diff --git a/.changeset/new-rules-teach.md b/.changeset/new-rules-teach.md new file mode 100644 index 0000000000..cae0215bfc --- /dev/null +++ b/.changeset/new-rules-teach.md @@ -0,0 +1,8 @@ +--- +'@backstage/catalog-client': minor +'@backstage/plugin-catalog-backend': minor +'@backstage/plugin-events-backend': minor +'@backstage/plugin-search-backend': minor +--- + +Internal updates to generated code. diff --git a/.changeset/ninety-panthers-provide.md b/.changeset/ninety-panthers-provide.md deleted file mode 100644 index 467344ae61..0000000000 --- a/.changeset/ninety-panthers-provide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -The `generate-patch` command now properly includes newly created files in the patch. diff --git a/.changeset/ninety-shirts-float.md b/.changeset/ninety-shirts-float.md deleted file mode 100644 index 4ff9a39560..0000000000 --- a/.changeset/ninety-shirts-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Align with type declaration of template filter/global function by supporting undefined as return value. diff --git a/.changeset/odd-apples-explain.md b/.changeset/odd-apples-explain.md new file mode 100644 index 0000000000..324d98b0f6 --- /dev/null +++ b/.changeset/odd-apples-explain.md @@ -0,0 +1,8 @@ +--- +'@backstage/plugin-auth-node': patch +'@backstage/plugin-permission-backend': patch +'@backstage/plugin-devtools-backend': patch +'@backstage/plugin-signals-backend': patch +--- + +Restrict `@types/express` version range from `*` to `^4.17.6`. diff --git a/.changeset/odd-days-push.md b/.changeset/odd-days-push.md new file mode 100644 index 0000000000..fd46de029f --- /dev/null +++ b/.changeset/odd-days-push.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-backend': patch +--- + +Deprecated root '/' endpoints, moving them under `/notifications` instead. diff --git a/.changeset/odd-worms-peel.md b/.changeset/odd-worms-peel.md new file mode 100644 index 0000000000..90e05f1e51 --- /dev/null +++ b/.changeset/odd-worms-peel.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Correctly report stitching queue length diff --git a/.changeset/old-pandas-act.md b/.changeset/old-pandas-act.md new file mode 100644 index 0000000000..7b88652342 --- /dev/null +++ b/.changeset/old-pandas-act.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-github': patch +--- + +Minor spell fix in action parameters diff --git a/.changeset/old-taxis-exist.md b/.changeset/old-taxis-exist.md new file mode 100644 index 0000000000..f2c7ac1f02 --- /dev/null +++ b/.changeset/old-taxis-exist.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-events-backend': patch +'@backstage/plugin-events-node': patch +--- + +Allow configuring a timeout for event bus polling requests. This can be set like so in your app-config: + +```yaml +events: + notifyTimeoutMs: 30000 +``` diff --git a/.changeset/olive-berries-jump.md b/.changeset/olive-berries-jump.md new file mode 100644 index 0000000000..d8e9fb1da6 --- /dev/null +++ b/.changeset/olive-berries-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-techdocs': patch +--- + +Added support for the Search bar in docs residing in the entity page tab, and not only the global "/docs" page. diff --git a/.changeset/orange-coins-confess.md b/.changeset/orange-coins-confess.md new file mode 100644 index 0000000000..8e8aefb096 --- /dev/null +++ b/.changeset/orange-coins-confess.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-devtools-backend': minor +--- + +**BREAKING** Removed support for what is known as the legacy backend, please use the New Backend System. diff --git a/.changeset/orange-moles-kick.md b/.changeset/orange-moles-kick.md new file mode 100644 index 0000000000..6e6054418e --- /dev/null +++ b/.changeset/orange-moles-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Emit scaffolder events using the optional `EventsService` diff --git a/.changeset/orange-moles-taste.md b/.changeset/orange-moles-taste.md deleted file mode 100644 index 79a5bd70ff..0000000000 --- a/.changeset/orange-moles-taste.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': minor -'@backstage/plugin-kubernetes-common': minor -'@backstage/plugin-kubernetes-react': minor -'@backstage/plugin-kubernetes-node': minor -'@backstage/plugin-kubernetes': minor ---- - -Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages diff --git a/.changeset/perfect-fishes-kick.md b/.changeset/perfect-fishes-kick.md new file mode 100644 index 0000000000..b9e7ade993 --- /dev/null +++ b/.changeset/perfect-fishes-kick.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-notifications-backend': minor +--- + +**BREAKING**: Removed redundant `/health` endpoint, switch to using [the built-in endpoint instead](https://backstage.io/docs/backend-system/core-services/root-health). diff --git a/.changeset/perfect-goats-mate.md b/.changeset/perfect-goats-mate.md deleted file mode 100644 index 6ad2884d08..0000000000 --- a/.changeset/perfect-goats-mate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/core-components': minor ---- - -The SupportButton component will now be hidden if no support config is specified in app-config diff --git a/.changeset/pink-bees-shake.md b/.changeset/pink-bees-shake.md new file mode 100644 index 0000000000..2d87b7ef6c --- /dev/null +++ b/.changeset/pink-bees-shake.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-node': patch +--- + +Make sure that isomorphic git push commands are not proxied. diff --git a/.changeset/pink-pets-jump.md b/.changeset/pink-pets-jump.md new file mode 100644 index 0000000000..d9bb97e36e --- /dev/null +++ b/.changeset/pink-pets-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Support `connection.type: cloudsql` in database client for usage with `@google-cloud/cloud-sql-connector` and `iam` auth diff --git a/.changeset/pink-schools-shave.md b/.changeset/pink-schools-shave.md deleted file mode 100644 index a7cce72d1f..0000000000 --- a/.changeset/pink-schools-shave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Improve UI consistency of default catalog filters diff --git a/.changeset/plenty-students-check.md b/.changeset/plenty-students-check.md deleted file mode 100644 index b83199f9e0..0000000000 --- a/.changeset/plenty-students-check.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'@backstage/core-components': patch ---- - -Adds the ability to mock a media query per break point and to change the active break point during a test. Usage example: - -```ts -const { set } = mockBreakpoint({ - initialBreakpoint: 'md', - queryBreakpointMap: { - '(min-width:1500px)': 'xl', - '(min-width:1000px)': 'lg', - '(min-width:700px)': 'md', - '(min-width:400px)': 'sm', - '(min-width:0px)': 'xs', - }, -}); -// assertions for when the active break point is "md" -set('lg'); -// assertions for when the active break point is "lg" -``` diff --git a/.changeset/forty-spoons-burn.md b/.changeset/polite-foxes-buy.md similarity index 59% rename from .changeset/forty-spoons-burn.md rename to .changeset/polite-foxes-buy.md index 627cb31970..a67af204e0 100644 --- a/.changeset/forty-spoons-burn.md +++ b/.changeset/polite-foxes-buy.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': patch --- -Fix tasks listing with postgres +Add fs:readdir to scaffolder startup diff --git a/.changeset/poor-hounds-jump.md b/.changeset/poor-hounds-jump.md new file mode 100644 index 0000000000..2f1abb8ce8 --- /dev/null +++ b/.changeset/poor-hounds-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Bumped the version range for `html-webpack-plugin` to fix the `htmlPluginExports.getCompilationHooks is not a function` error when using experimental Rspack. diff --git a/.changeset/popular-donkeys-rhyme.md b/.changeset/popular-donkeys-rhyme.md new file mode 100644 index 0000000000..90195ff999 --- /dev/null +++ b/.changeset/popular-donkeys-rhyme.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Added `@backstage/cli/config/prettier` as a replacement for `@spotify/prettier-config`, but with the same configuration. diff --git a/.changeset/pre.json b/.changeset/pre.json index eb945eac0c..9e3ea04b65 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -2,309 +2,313 @@ "mode": "exit", "tag": "next", "initialVersions": { - "example-app": "0.2.102", - "@backstage/app-defaults": "1.5.12", - "example-app-next": "0.0.16", - "app-next-example-plugin": "0.0.16", - "example-backend": "0.0.31", - "@backstage/backend-app-api": "1.0.1", - "@backstage/backend-defaults": "0.5.1", + "example-app": "0.2.103", + "@backstage/app-defaults": "1.5.13", + "example-app-next": "0.0.17", + "app-next-example-plugin": "0.0.17", + "example-backend": "0.0.32", + "@backstage/backend-app-api": "1.0.2", + "@backstage/backend-defaults": "0.5.3", "@backstage/backend-dev-utils": "0.1.5", - "@backstage/backend-dynamic-feature-service": "0.4.2", - "example-backend-legacy": "0.2.103", - "@backstage/backend-openapi-utils": "0.2.0", - "@backstage/backend-plugin-api": "1.0.1", - "@backstage/backend-test-utils": "1.0.1", - "@backstage/catalog-client": "1.7.1", - "@backstage/catalog-model": "1.7.0", - "@backstage/cli": "0.28.0", - "@backstage/cli-common": "0.1.14", - "@backstage/cli-node": "0.2.9", - "@backstage/codemods": "0.1.51", - "@backstage/config": "1.2.0", - "@backstage/config-loader": "1.9.1", - "@backstage/core-app-api": "1.15.1", - "@backstage/core-compat-api": "0.3.1", - "@backstage/core-components": "0.15.1", - "@backstage/core-plugin-api": "1.10.0", - "@backstage/create-app": "0.5.21", - "@backstage/dev-utils": "1.1.2", - "e2e-test": "0.2.21", + "@backstage/backend-dynamic-feature-service": "0.5.0", + "example-backend-legacy": "0.2.104", + "@backstage/backend-openapi-utils": "0.3.0", + "@backstage/backend-plugin-api": "1.0.2", + "@backstage/backend-test-utils": "1.1.0", + "@backstage/catalog-client": "1.8.0", + "@backstage/catalog-model": "1.7.1", + "@backstage/cli": "0.29.0", + "@backstage/cli-common": "0.1.15", + "@backstage/cli-node": "0.2.10", + "@backstage/codemods": "0.1.52", + "@backstage/config": "1.3.0", + "@backstage/config-loader": "1.9.2", + "@backstage/core-app-api": "1.15.2", + "@backstage/core-compat-api": "0.3.2", + "@backstage/core-components": "0.16.0", + "@backstage/core-plugin-api": "1.10.1", + "@backstage/create-app": "0.5.22", + "@backstage/dev-utils": "1.1.3", + "e2e-test": "0.2.22", "@backstage/e2e-test-utils": "0.1.1", - "@backstage/errors": "1.2.4", + "@backstage/errors": "1.2.5", "@backstage/eslint-plugin": "0.1.10", - "@backstage/frontend-app-api": "0.10.0", - "@backstage/frontend-defaults": "0.1.1", - "@internal/frontend": "0.0.2", - "@backstage/frontend-plugin-api": "0.9.0", - "@backstage/frontend-test-utils": "0.2.1", - "@backstage/integration": "1.15.1", - "@backstage/integration-aws-node": "0.1.12", - "@backstage/integration-react": "1.2.0", + "@backstage/frontend-app-api": "0.10.1", + "@backstage/frontend-defaults": "0.1.2", + "@internal/frontend": "0.0.3", + "@backstage/frontend-plugin-api": "0.9.1", + "@backstage/frontend-test-utils": "0.2.2", + "@backstage/integration": "1.15.2", + "@backstage/integration-aws-node": "0.1.13", + "@backstage/integration-react": "1.2.1", "@internal/opaque": "0.0.1", "@backstage/release-manifests": "0.0.11", - "@backstage/repo-tools": "0.10.0", - "@internal/scaffolder": "0.0.2", - "@techdocs/cli": "1.8.20", - "techdocs-cli-embedded-app": "0.2.101", - "@backstage/test-utils": "1.7.0", - "@backstage/theme": "0.6.0", - "@backstage/types": "1.1.1", + "@backstage/repo-tools": "0.11.0", + "@internal/scaffolder": "0.0.3", + "@techdocs/cli": "1.8.22", + "techdocs-cli-embedded-app": "0.2.102", + "@backstage/test-utils": "1.7.1", + "@backstage/theme": "0.6.1", + "@backstage/types": "1.2.0", "@backstage/version-bridge": "1.0.10", - "yarn-plugin-backstage": "0.0.2", - "@backstage/plugin-api-docs": "0.11.11", + "yarn-plugin-backstage": "0.0.3", + "@backstage/plugin-api-docs": "0.12.0", "@backstage/plugin-api-docs-module-protoc-gen-doc": "0.1.8", - "@backstage/plugin-app": "0.1.1", - "@backstage/plugin-app-backend": "0.3.76", - "@backstage/plugin-app-node": "0.1.26", - "@backstage/plugin-app-visualizer": "0.1.11", - "@backstage/plugin-auth-backend": "0.23.1", - "@backstage/plugin-auth-backend-module-atlassian-provider": "0.3.1", - "@backstage/plugin-auth-backend-module-auth0-provider": "0.1.1", - "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.1.1", - "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.3.1", - "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.3.1", - "@backstage/plugin-auth-backend-module-github-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-gitlab-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-google-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-guest-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-microsoft-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-oauth2-provider": "0.3.1", - "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-oidc-provider": "0.3.1", - "@backstage/plugin-auth-backend-module-okta-provider": "0.1.1", - "@backstage/plugin-auth-backend-module-onelogin-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-pinniped-provider": "0.2.1", - "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.4.0", - "@backstage/plugin-auth-node": "0.5.3", - "@backstage/plugin-auth-react": "0.1.7", - "@backstage/plugin-bitbucket-cloud-common": "0.2.24", - "@backstage/plugin-catalog": "1.24.0", - "@backstage/plugin-catalog-backend": "1.27.0", - "@backstage/plugin-catalog-backend-module-aws": "0.4.3", - "@backstage/plugin-catalog-backend-module-azure": "0.2.3", - "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.4.1", - "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.4.0", - "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.2.3", - "@backstage/plugin-catalog-backend-module-gcp": "0.3.1", - "@backstage/plugin-catalog-backend-module-gerrit": "0.2.3", - "@backstage/plugin-catalog-backend-module-github": "0.7.5", - "@backstage/plugin-catalog-backend-module-github-org": "0.3.2", - "@backstage/plugin-catalog-backend-module-gitlab": "0.4.3", - "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.1", - "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.5.5", - "@backstage/plugin-catalog-backend-module-ldap": "0.9.1", - "@backstage/plugin-catalog-backend-module-logs": "0.1.2", - "@backstage/plugin-catalog-backend-module-msgraph": "0.6.3", - "@backstage/plugin-catalog-backend-module-openapi": "0.2.2", - "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.3", - "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.1", - "@backstage/plugin-catalog-backend-module-unprocessed": "0.5.1", - "@backstage/plugin-catalog-common": "1.1.0", - "@backstage/plugin-catalog-graph": "0.4.11", - "@backstage/plugin-catalog-import": "0.12.5", - "@backstage/plugin-catalog-node": "1.13.1", - "@backstage/plugin-catalog-react": "1.14.0", - "@backstage/plugin-catalog-unprocessed-entities": "0.2.9", - "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.4", - "@backstage/plugin-config-schema": "0.1.60", - "@backstage/plugin-devtools": "0.1.19", - "@backstage/plugin-devtools-backend": "0.4.1", - "@backstage/plugin-devtools-common": "0.1.12", - "@backstage/plugin-events-backend": "0.3.13", - "@backstage/plugin-events-backend-module-aws-sqs": "0.4.3", - "@backstage/plugin-events-backend-module-azure": "0.2.12", - "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.12", - "@backstage/plugin-events-backend-module-gerrit": "0.2.12", - "@backstage/plugin-events-backend-module-github": "0.2.12", - "@backstage/plugin-events-backend-module-gitlab": "0.2.12", - "@backstage/plugin-events-backend-test-utils": "0.1.36", - "@backstage/plugin-events-node": "0.4.1", - "@internal/plugin-todo-list": "1.0.32", - "@internal/plugin-todo-list-backend": "1.0.32", - "@internal/plugin-todo-list-common": "1.0.21", - "@backstage/plugin-home": "0.8.0", - "@backstage/plugin-home-react": "0.1.18", - "@backstage/plugin-kubernetes": "0.11.16", - "@backstage/plugin-kubernetes-backend": "0.18.7", - "@backstage/plugin-kubernetes-cluster": "0.0.17", - "@backstage/plugin-kubernetes-common": "0.8.3", - "@backstage/plugin-kubernetes-node": "0.1.20", - "@backstage/plugin-kubernetes-react": "0.4.4", - "@backstage/plugin-notifications": "0.3.2", - "@backstage/plugin-notifications-backend": "0.4.1", - "@backstage/plugin-notifications-backend-module-email": "0.3.1", - "@backstage/plugin-notifications-common": "0.0.5", - "@backstage/plugin-notifications-node": "0.2.7", - "@backstage/plugin-org": "0.6.31", - "@backstage/plugin-org-react": "0.1.30", - "@backstage/plugin-permission-backend": "0.5.50", - "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.1", - "@backstage/plugin-permission-common": "0.8.1", - "@backstage/plugin-permission-node": "0.8.4", - "@backstage/plugin-permission-react": "0.4.27", - "@backstage/plugin-proxy-backend": "0.5.7", - "@backstage/plugin-scaffolder": "1.26.0", - "@backstage/plugin-scaffolder-backend": "1.26.0", - "@backstage/plugin-scaffolder-backend-module-azure": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.1", - "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.1", - "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.1", - "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-github": "0.5.1", - "@backstage/plugin-scaffolder-backend-module-gitlab": "0.6.0", - "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.1", - "@backstage/plugin-scaffolder-backend-module-rails": "0.5.1", - "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.1", - "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.1", - "@backstage/plugin-scaffolder-common": "1.5.6", - "@backstage/plugin-scaffolder-node": "0.5.0", - "@backstage/plugin-scaffolder-node-test-utils": "0.1.13", - "@backstage/plugin-scaffolder-react": "1.13.0", - "@backstage/plugin-search": "1.4.18", - "@backstage/plugin-search-backend": "1.6.0", - "@backstage/plugin-search-backend-module-catalog": "0.2.3", - "@backstage/plugin-search-backend-module-elasticsearch": "1.6.0", - "@backstage/plugin-search-backend-module-explore": "0.2.3", - "@backstage/plugin-search-backend-module-pg": "0.5.36", - "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.1", - "@backstage/plugin-search-backend-module-techdocs": "0.3.0", - "@backstage/plugin-search-backend-node": "1.3.3", - "@backstage/plugin-search-common": "1.2.14", - "@backstage/plugin-search-react": "1.8.1", - "@backstage/plugin-signals": "0.0.11", - "@backstage/plugin-signals-backend": "0.2.1", - "@backstage/plugin-signals-node": "0.1.12", - "@backstage/plugin-signals-react": "0.0.6", - "@backstage/plugin-techdocs": "1.11.0", - "@backstage/plugin-techdocs-addons-test-utils": "1.0.40", - "@backstage/plugin-techdocs-backend": "1.11.0", + "@backstage/plugin-app": "0.1.2", + "@backstage/plugin-app-backend": "0.4.0", + "@backstage/plugin-app-node": "0.1.27", + "@backstage/plugin-app-visualizer": "0.1.12", + "@backstage/plugin-auth-backend": "0.24.0", + "@backstage/plugin-auth-backend-module-atlassian-provider": "0.3.2", + "@backstage/plugin-auth-backend-module-auth0-provider": "0.1.2", + "@backstage/plugin-auth-backend-module-aws-alb-provider": "0.3.0", + "@backstage/plugin-auth-backend-module-azure-easyauth-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-bitbucket-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-bitbucket-server-provider": "0.1.2", + "@backstage/plugin-auth-backend-module-cloudflare-access-provider": "0.3.2", + "@backstage/plugin-auth-backend-module-gcp-iap-provider": "0.3.2", + "@backstage/plugin-auth-backend-module-github-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-gitlab-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-google-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-guest-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-microsoft-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-oauth2-provider": "0.3.2", + "@backstage/plugin-auth-backend-module-oauth2-proxy-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-oidc-provider": "0.3.2", + "@backstage/plugin-auth-backend-module-okta-provider": "0.1.2", + "@backstage/plugin-auth-backend-module-onelogin-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-pinniped-provider": "0.2.2", + "@backstage/plugin-auth-backend-module-vmware-cloud-provider": "0.4.1", + "@backstage/plugin-auth-node": "0.5.4", + "@backstage/plugin-auth-react": "0.1.8", + "@backstage/plugin-bitbucket-cloud-common": "0.2.25", + "@backstage/plugin-catalog": "1.25.0", + "@backstage/plugin-catalog-backend": "1.28.0", + "@backstage/plugin-catalog-backend-module-aws": "0.4.5", + "@backstage/plugin-catalog-backend-module-azure": "0.2.4", + "@backstage/plugin-catalog-backend-module-backstage-openapi": "0.4.2", + "@backstage/plugin-catalog-backend-module-bitbucket-cloud": "0.4.2", + "@backstage/plugin-catalog-backend-module-bitbucket-server": "0.2.4", + "@backstage/plugin-catalog-backend-module-gcp": "0.3.2", + "@backstage/plugin-catalog-backend-module-gerrit": "0.2.4", + "@backstage/plugin-catalog-backend-module-github": "0.7.7", + "@backstage/plugin-catalog-backend-module-github-org": "0.3.4", + "@backstage/plugin-catalog-backend-module-gitlab": "0.5.0", + "@backstage/plugin-catalog-backend-module-gitlab-org": "0.2.3", + "@backstage/plugin-catalog-backend-module-incremental-ingestion": "0.6.0", + "@backstage/plugin-catalog-backend-module-ldap": "0.10.0", + "@backstage/plugin-catalog-backend-module-logs": "0.1.4", + "@backstage/plugin-catalog-backend-module-msgraph": "0.6.4", + "@backstage/plugin-catalog-backend-module-openapi": "0.2.4", + "@backstage/plugin-catalog-backend-module-puppetdb": "0.2.4", + "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "0.2.2", + "@backstage/plugin-catalog-backend-module-unprocessed": "0.5.2", + "@backstage/plugin-catalog-common": "1.1.1", + "@backstage/plugin-catalog-graph": "0.4.12", + "@backstage/plugin-catalog-import": "0.12.6", + "@backstage/plugin-catalog-node": "1.14.0", + "@backstage/plugin-catalog-react": "1.14.1", + "@backstage/plugin-catalog-unprocessed-entities": "0.2.10", + "@backstage/plugin-catalog-unprocessed-entities-common": "0.0.5", + "@backstage/plugin-config-schema": "0.1.61", + "@backstage/plugin-devtools": "0.1.20", + "@backstage/plugin-devtools-backend": "0.4.2", + "@backstage/plugin-devtools-common": "0.1.13", + "@backstage/plugin-events-backend": "0.3.16", + "@backstage/plugin-events-backend-module-aws-sqs": "0.4.5", + "@backstage/plugin-events-backend-module-azure": "0.2.14", + "@backstage/plugin-events-backend-module-bitbucket-cloud": "0.2.14", + "@backstage/plugin-events-backend-module-gerrit": "0.2.14", + "@backstage/plugin-events-backend-module-github": "0.2.14", + "@backstage/plugin-events-backend-module-gitlab": "0.2.14", + "@backstage/plugin-events-backend-test-utils": "0.1.38", + "@backstage/plugin-events-node": "0.4.5", + "@internal/plugin-todo-list": "1.0.33", + "@internal/plugin-todo-list-backend": "1.0.33", + "@internal/plugin-todo-list-common": "1.0.22", + "@backstage/plugin-home": "0.8.1", + "@backstage/plugin-home-react": "0.1.19", + "@backstage/plugin-kubernetes": "0.12.0", + "@backstage/plugin-kubernetes-backend": "0.19.0", + "@backstage/plugin-kubernetes-cluster": "0.0.18", + "@backstage/plugin-kubernetes-common": "0.9.0", + "@backstage/plugin-kubernetes-node": "0.2.0", + "@backstage/plugin-kubernetes-react": "0.5.0", + "@backstage/plugin-notifications": "0.4.0", + "@backstage/plugin-notifications-backend": "0.4.3", + "@backstage/plugin-notifications-backend-module-email": "0.3.3", + "@backstage/plugin-notifications-common": "0.0.6", + "@backstage/plugin-notifications-node": "0.2.9", + "@backstage/plugin-org": "0.6.32", + "@backstage/plugin-org-react": "0.1.31", + "@backstage/plugin-permission-backend": "0.5.51", + "@backstage/plugin-permission-backend-module-allow-all-policy": "0.2.2", + "@backstage/plugin-permission-common": "0.8.2", + "@backstage/plugin-permission-node": "0.8.5", + "@backstage/plugin-permission-react": "0.4.28", + "@backstage/plugin-proxy-backend": "0.5.8", + "@backstage/plugin-scaffolder": "1.27.0", + "@backstage/plugin-scaffolder-backend": "1.27.0", + "@backstage/plugin-scaffolder-backend-module-azure": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-bitbucket": "0.3.2", + "@backstage/plugin-scaffolder-backend-module-bitbucket-cloud": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-confluence-to-markdown": "0.3.2", + "@backstage/plugin-scaffolder-backend-module-cookiecutter": "0.3.3", + "@backstage/plugin-scaffolder-backend-module-gcp": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-gerrit": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-gitea": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-github": "0.5.2", + "@backstage/plugin-scaffolder-backend-module-gitlab": "0.6.1", + "@backstage/plugin-scaffolder-backend-module-notifications": "0.1.3", + "@backstage/plugin-scaffolder-backend-module-rails": "0.5.2", + "@backstage/plugin-scaffolder-backend-module-sentry": "0.2.2", + "@backstage/plugin-scaffolder-backend-module-yeoman": "0.4.3", + "@backstage/plugin-scaffolder-common": "1.5.7", + "@backstage/plugin-scaffolder-node": "0.6.0", + "@backstage/plugin-scaffolder-node-test-utils": "0.1.15", + "@backstage/plugin-scaffolder-react": "1.14.0", + "@backstage/plugin-search": "1.4.19", + "@backstage/plugin-search-backend": "1.7.0", + "@backstage/plugin-search-backend-module-catalog": "0.2.5", + "@backstage/plugin-search-backend-module-elasticsearch": "1.6.2", + "@backstage/plugin-search-backend-module-explore": "0.2.5", + "@backstage/plugin-search-backend-module-pg": "0.5.38", + "@backstage/plugin-search-backend-module-stack-overflow-collator": "0.3.3", + "@backstage/plugin-search-backend-module-techdocs": "0.3.2", + "@backstage/plugin-search-backend-node": "1.3.5", + "@backstage/plugin-search-common": "1.2.15", + "@backstage/plugin-search-react": "1.8.2", + "@backstage/plugin-signals": "0.0.12", + "@backstage/plugin-signals-backend": "0.2.3", + "@backstage/plugin-signals-node": "0.1.14", + "@backstage/plugin-signals-react": "0.0.7", + "@backstage/plugin-techdocs": "1.11.1", + "@backstage/plugin-techdocs-addons-test-utils": "1.0.41", + "@backstage/plugin-techdocs-backend": "1.11.2", "@backstage/plugin-techdocs-common": "0.1.0", - "@backstage/plugin-techdocs-module-addons-contrib": "1.1.16", - "@backstage/plugin-techdocs-node": "1.12.12", - "@backstage/plugin-techdocs-react": "1.2.9", - "@backstage/plugin-user-settings": "0.8.14", - "@backstage/plugin-user-settings-backend": "0.2.25", - "@backstage/plugin-user-settings-common": "0.0.1" + "@backstage/plugin-techdocs-module-addons-contrib": "1.1.17", + "@backstage/plugin-techdocs-node": "1.12.13", + "@backstage/plugin-techdocs-react": "1.2.10", + "@backstage/plugin-user-settings": "0.8.15", + "@backstage/plugin-user-settings-backend": "0.2.27", + "@backstage/plugin-user-settings-common": "0.0.1", + "@backstage/canon": "0.0.0" }, "changesets": [ - "afraid-bananas-behave", - "afraid-carrots-greet", - "big-tips-heal", - "bright-buckets-laugh", - "bright-singers-do", - "chilled-taxis-dance", - "create-app-1729608704", - "create-app-1730809984", - "curvy-bears-nail", - "cyan-trees-bow", - "early-cobras-compare", - "early-monkeys-hammer", - "empty-lobsters-wait", - "few-hornets-rush", - "flat-feet-do", - "forty-pets-wave", - "forty-spoons-burn", - "fresh-jeans-relate", - "friendly-hats-push", - "friendly-kids-judge", - "friendly-melons-shake", - "green-tools-arrive", - "grumpy-shoes-return", - "healthy-bags-jog", - "healthy-lions-judge", - "healthy-tables-wonder", - "heavy-mice-raise", - "heavy-phones-shave", - "hungry-cats-juggle", - "hungry-owls-sell", - "itchy-elephants-trade", - "khaki-fireants-march", - "late-kings-wave", - "lemon-gifts-crash", - "little-rivers-deny", - "loud-plants-dream", - "loud-trainers-yawn", - "lucky-bananas-eat", - "lucky-snakes-complain", - "mean-years-deliver", - "metal-files-itch", - "mighty-jobs-unite", - "mighty-spoons-suffer", - "neat-buttons-wait", - "ninety-panthers-provide", - "ninety-shirts-float", - "orange-moles-taste", - "perfect-goats-mate", - "pink-schools-shave", - "plenty-students-check", - "pretty-zebras-listen", - "purple-masks-swim", - "quick-cougars-fry", - "rare-otters-judge", - "rare-trains-scream", - "red-fishes-press", - "renovate-3d822ce", - "renovate-4635182", - "renovate-6193787", - "renovate-7a33477", - "renovate-7b59eed", - "renovate-b2c2aaf", - "renovate-bcc9782", - "rotten-lions-cover", - "rotten-needles-relax", - "selfish-ads-count", - "selfish-spies-cough", - "serious-penguins-remain", - "seven-berries-listen", - "seven-hotels-move", - "shiny-falcons-fly", - "short-geckos-sniff", - "short-pots-remember", - "shy-clouds-brake", - "shy-pots-speak", - "shy-rats-hear", - "silent-wasps-whisper", - "silly-kiwis-destroy", - "silver-ears-grin", - "silver-kings-sort", - "six-beds-exercise", - "slimy-jobs-scream", - "slimy-penguins-care", - "slow-mayflies-sleep", - "slow-shrimps-call", - "smart-bags-sell", - "soft-turkeys-tie", - "spotty-snails-worry", - "strange-clocks-pretend", - "strong-paws-change", - "swift-laws-applaud", - "ten-hats-appear", - "ten-pears-unite", - "tender-feet-scream", - "thick-trees-worry", - "three-mangos-dance", - "tough-onions-dance", - "tricky-crabs-lick", - "twelve-masks-call", - "two-donuts-float", - "unlucky-countries-shop", - "violet-ears-dance", - "violet-parrots-knock", - "warm-tomatoes-develop", - "wild-experts-unite", - "wise-avocados-behave", - "wise-snakes-sleep", - "witty-bobcats-push", - "witty-socks-repeat", - "yellow-horses-pretend", - "young-penguins-act" + "beige-chicken-type", + "brave-maps-deliver", + "brave-teachers-mate", + "brown-monkeys-ring", + "chatty-weeks-impress", + "chilly-games-trade", + "cold-icons-worry", + "cold-jeans-stare", + "cool-days-sparkle", + "cuddly-chicken-wink", + "cuddly-schools-scream", + "curly-hats-tell", + "cyan-rocks-divide", + "dry-badgers-prove", + "dry-needles-taste", + "dull-bulldogs-learn", + "dull-ties-film", + "empty-bugs-deliver", + "empty-colts-promise", + "empty-ways-push", + "fast-cheetahs-deliver", + "few-colts-train", + "few-pillows-remember", + "fifty-countries-decide", + "five-goats-travel", + "fluffy-cobras-sort", + "fluffy-falcons-shout", + "fluffy-zebras-cheer", + "forty-apples-complain", + "forty-ravens-fry", + "friendly-dots-thank", + "gold-crabs-agree", + "gold-stingrays-cross", + "gorgeous-panthers-count", + "great-buttons-cross", + "green-carpets-smell", + "happy-forks-listen", + "healthy-years-begin", + "heavy-needles-poke", + "heavy-tomatoes-laugh", + "honest-hornets-double", + "hungry-hairs-wait", + "itchy-rats-pump", + "itchy-ravens-punch", + "khaki-ladybugs-swim", + "khaki-shrimps-tease", + "large-birds-watch", + "lazy-pants-attack", + "lazy-years-float", + "lemon-bulldogs-study", + "lucky-crabs-vanish", + "mean-shirts-design", + "mighty-birds-rest", + "neat-insects-cough", + "new-pandas-perform", + "new-rules-teach", + "odd-apples-explain", + "odd-days-push", + "odd-worms-peel", + "old-taxis-exist", + "olive-berries-jump", + "orange-coins-confess", + "orange-moles-kick", + "perfect-fishes-kick", + "pink-bees-shake", + "pink-pets-jump", + "polite-foxes-buy", + "poor-hounds-jump", + "popular-donkeys-rhyme", + "pretty-kiwis-travel", + "real-shirts-cry", + "renovate-998a490", + "renovate-9a9f6ed", + "renovate-a5f3bd6", + "renovate-e689a2c", + "rich-beers-eat", + "rich-maps-invite", + "rich-suns-drive", + "rollup-fix-forward", + "rollup-release-borked-packages", + "rude-pears-tie", + "seven-bulldogs-count", + "short-baboons-search", + "shy-teachers-count", + "silent-pigs-collect", + "silver-actors-care", + "six-eels-add", + "sixty-shirts-rescue", + "slow-horses-destroy", + "slow-singers-jump", + "small-boxes-enjoy", + "smart-islands-judge", + "smooth-bikes-sparkle", + "spotty-shoes-exercise", + "stale-hats-exist", + "stale-rats-tease", + "strange-brooms-check", + "strong-papayas-remember", + "swift-kangaroos-drop", + "tall-comics-heal", + "ten-keys-nail", + "thick-items-bathe", + "thin-hotels-explode", + "tiny-mice-run", + "twenty-monkeys-applaud", + "twenty-parents-judge", + "violet-snakes-laugh", + "warm-pumpkins-bathe", + "weak-avocados-suffer", + "weak-meals-doubt", + "wet-rats-exist", + "young-carrots-collect", + "young-cobras-add", + "young-months-admire" ] } diff --git a/.changeset/pretty-kiwis-travel.md b/.changeset/pretty-kiwis-travel.md new file mode 100644 index 0000000000..f3d5cbeb27 --- /dev/null +++ b/.changeset/pretty-kiwis-travel.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Implements the `DefaultRootLifecycleService.addBeforeShutdownHook` method, and updates `DefaultRootHttpRouterService` and `DefaultRootHealthService` to listen to that event to stop accepting traffic and close service connections. diff --git a/.changeset/pretty-ligers-bake.md b/.changeset/pretty-ligers-bake.md deleted file mode 100644 index 871154f974..0000000000 --- a/.changeset/pretty-ligers-bake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-notifications': patch ---- - -The notification's title is emphasized to be clearly distinguished from the description. diff --git a/.changeset/pretty-zebras-listen.md b/.changeset/pretty-zebras-listen.md deleted file mode 100644 index d7ee0faef4..0000000000 --- a/.changeset/pretty-zebras-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue where the `raw-loader` for loading HTML templates was not resolved from the context of the CLI package. diff --git a/.changeset/purple-masks-swim.md b/.changeset/purple-masks-swim.md deleted file mode 100644 index d285712f64..0000000000 --- a/.changeset/purple-masks-swim.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-kubernetes-backend': patch ---- - -Adapted the config.d.ts for custom k8s cluster authProvider implementations diff --git a/.changeset/quick-cougars-fry.md b/.changeset/quick-cougars-fry.md deleted file mode 100644 index 6ae8b66eda..0000000000 --- a/.changeset/quick-cougars-fry.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@backstage/plugin-home': patch ---- - -Improve Starred Entities UI to reduce whitespace and provide more context on the entities: - -- Use the Entity Presentation API (via ``) to display the entity's name -- Component's `kind` and `spec.type` are displayed as a secondary text -- List items are condensed to reduce unnecessary spacing diff --git a/.changeset/rare-otters-judge.md b/.changeset/rare-otters-judge.md deleted file mode 100644 index 3c3f91e094..0000000000 --- a/.changeset/rare-otters-judge.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-auth-node': patch ---- - -Browsers silently drop cookies that exceed 4KB, which can be problematic for refresh tokens and other large cookies.This update ensures that large cookies, like refresh tokens, are not dropped by browsers, maintaining the integrity of the authentication process. The changes include both the implementation of the cookie splitting logic and corresponding tests to validate the new functionality. diff --git a/.changeset/rare-trains-scream.md b/.changeset/rare-trains-scream.md deleted file mode 100644 index e6a3a141fa..0000000000 --- a/.changeset/rare-trains-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -fix(scaffolder): use `onInputChange` in `RepoUrlPicker` to fix issue with the value not updating properly diff --git a/.changeset/real-shirts-cry.md b/.changeset/real-shirts-cry.md new file mode 100644 index 0000000000..78056368ae --- /dev/null +++ b/.changeset/real-shirts-cry.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli-node': patch +--- + +Internal refactor diff --git a/.changeset/red-fishes-press.md b/.changeset/red-fishes-press.md deleted file mode 100644 index 8493ddf446..0000000000 --- a/.changeset/red-fishes-press.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Added DomPurify sanitizer configuration for custom elements implementing RFC https://github.com/backstage/backstage/issues/26988. -See https://backstage.io/docs/features/techdocs/how-to-guides#how-to-enable-custom-elements-in-techdocs for how to enable it in the configuration. diff --git a/.changeset/renovate-297315f.md b/.changeset/renovate-297315f.md deleted file mode 100644 index 6904a54681..0000000000 --- a/.changeset/renovate-297315f.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `vite` to `^5.0.0`. diff --git a/.changeset/renovate-3d822ce.md b/.changeset/renovate-3d822ce.md deleted file mode 100644 index 805b924b3b..0000000000 --- a/.changeset/renovate-3d822ce.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-elasticsearch': patch ---- - -Updated dependency `@short.io/opensearch-mock` to `^0.4.0`. diff --git a/.changeset/renovate-4635182.md b/.changeset/renovate-4635182.md deleted file mode 100644 index c75b098e23..0000000000 --- a/.changeset/renovate-4635182.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': patch -'@backstage/repo-tools': patch -'@backstage/plugin-bitbucket-cloud-common': patch ---- - -Updated dependency `ts-morph` to `^24.0.0`. diff --git a/.changeset/renovate-6193787.md b/.changeset/renovate-6193787.md deleted file mode 100644 index ce392b7c81..0000000000 --- a/.changeset/renovate-6193787.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `css-loader` to `^7.0.0`. diff --git a/.changeset/renovate-7a33477.md b/.changeset/renovate-7a33477.md deleted file mode 100644 index daf17a280f..0000000000 --- a/.changeset/renovate-7a33477.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `@module-federation/enhanced` to `^0.7.0`. diff --git a/.changeset/renovate-7b59eed.md b/.changeset/renovate-7b59eed.md deleted file mode 100644 index 8031f9c4e7..0000000000 --- a/.changeset/renovate-7b59eed.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Updated dependency `del` to `^8.0.0`. diff --git a/.changeset/renovate-998a490.md b/.changeset/renovate-998a490.md new file mode 100644 index 0000000000..8def7d49cd --- /dev/null +++ b/.changeset/renovate-998a490.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Updated dependency `flatted` to `3.3.2`. diff --git a/.changeset/renovate-9a9f6ed.md b/.changeset/renovate-9a9f6ed.md new file mode 100644 index 0000000000..9dad75cc3e --- /dev/null +++ b/.changeset/renovate-9a9f6ed.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Updated dependency `@module-federation/enhanced` to `^0.8.0`. diff --git a/.changeset/renovate-a5f3bd6.md b/.changeset/renovate-a5f3bd6.md new file mode 100644 index 0000000000..9911fd311f --- /dev/null +++ b/.changeset/renovate-a5f3bd6.md @@ -0,0 +1,11 @@ +--- +'@backstage/plugin-home-react': patch +'@backstage/plugin-home': patch +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Updated dependency `@rjsf/utils` to `5.23.1`. +Updated dependency `@rjsf/core` to `5.23.1`. +Updated dependency `@rjsf/material-ui` to `5.23.1`. +Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. diff --git a/.changeset/renovate-b2c2aaf.md b/.changeset/renovate-b2c2aaf.md deleted file mode 100644 index b6e7a8c029..0000000000 --- a/.changeset/renovate-b2c2aaf.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Updated dependency `idb-keyval` to `5.1.5`. diff --git a/.changeset/renovate-bcc9782.md b/.changeset/renovate-bcc9782.md deleted file mode 100644 index 56b6704f79..0000000000 --- a/.changeset/renovate-bcc9782.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-explore': patch ---- - -Updated dependency `@backstage-community/plugin-explore-common` to `^0.0.7`. diff --git a/.changeset/renovate-e689a2c.md b/.changeset/renovate-e689a2c.md new file mode 100644 index 0000000000..7e4f999289 --- /dev/null +++ b/.changeset/renovate-e689a2c.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-compat-api': patch +--- + +Updated dependency `@oriflame/backstage-plugin-score-card` to `^0.9.0`. diff --git a/.changeset/renovate-f322bf6.md b/.changeset/renovate-f322bf6.md deleted file mode 100644 index 370c832ea5..0000000000 --- a/.changeset/renovate-f322bf6.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-openapi': patch ---- - -Updated dependency `@apidevtools/json-schema-ref-parser` to `^11.0.0`. diff --git a/.changeset/rich-beers-eat.md b/.changeset/rich-beers-eat.md new file mode 100644 index 0000000000..55115e929e --- /dev/null +++ b/.changeset/rich-beers-eat.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Wire up the events together in the new backend system diff --git a/.changeset/rich-maps-invite.md b/.changeset/rich-maps-invite.md new file mode 100644 index 0000000000..927d8e9382 --- /dev/null +++ b/.changeset/rich-maps-invite.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-permission-node': patch +--- + +The `createPermissionIntegrationRouter` function now detects and prevents the exposure of duplicate permissions. diff --git a/.changeset/rich-suns-drive.md b/.changeset/rich-suns-drive.md new file mode 100644 index 0000000000..0b2eb85a5b --- /dev/null +++ b/.changeset/rich-suns-drive.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-openapi-utils': minor +--- + +Fixed a Typescript error when trying to use the new OpenAPI server-side generated code. diff --git a/.changeset/rollup-fix-forward.md b/.changeset/rollup-fix-forward.md new file mode 100644 index 0000000000..681812a134 --- /dev/null +++ b/.changeset/rollup-fix-forward.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Update `rollup` to avoid issues with build output when running `backstage-cli package build`. diff --git a/.changeset/rollup-release-borked-packages.md b/.changeset/rollup-release-borked-packages.md new file mode 100644 index 0000000000..f13d7d2de7 --- /dev/null +++ b/.changeset/rollup-release-borked-packages.md @@ -0,0 +1,12 @@ +--- +'@backstage/cli': patch +'@backstage/frontend-plugin-api': patch +'@backstage/repo-tools': patch +'@backstage/theme': patch +'@backstage/plugin-app': patch +'@backstage/plugin-catalog-backend-module-ldap': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket': patch +'@backstage/plugin-techdocs-node': patch +--- + +Fixed a bug that caused missing code in published packages. diff --git a/.changeset/rotten-lions-cover.md b/.changeset/rotten-lions-cover.md deleted file mode 100644 index f64e8209b9..0000000000 --- a/.changeset/rotten-lions-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-techdocs': patch ---- - -Removed `canvas` dev dependency. diff --git a/.changeset/rotten-mangos-hug.md b/.changeset/rotten-mangos-hug.md deleted file mode 100644 index 022d3f3d45..0000000000 --- a/.changeset/rotten-mangos-hug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-github': patch ---- - -Fixed an issue in `GithubOrgEntityProvider` that caused an error when processing teams without a parent. diff --git a/.changeset/rotten-needles-relax.md b/.changeset/rotten-needles-relax.md deleted file mode 100644 index ef389402aa..0000000000 --- a/.changeset/rotten-needles-relax.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-catalog-node': minor ---- - -The `catalogServiceRef` now has its own accompanying `CatalogService` interface that requires Backstage `credentials` objects to be passed. This new version of the `catalogServiceRef` has been promoted and is now available via the main `@backstage/plugin-catalog-node` entry point. - -The old `catalogServiceRef` with the old `CatalogApi` type is still available from the `/alpha` entry point. diff --git a/.changeset/rude-pears-tie.md b/.changeset/rude-pears-tie.md new file mode 100644 index 0000000000..e29d517959 --- /dev/null +++ b/.changeset/rude-pears-tie.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Remove use of the `stoppable` library on the `DefaultRootHttpRouterService` as Node's native http server [close](https://nodejs.org/api/http.html#serverclosecallback) method already drains requests. diff --git a/.changeset/rude-shrimps-brake.md b/.changeset/rude-shrimps-brake.md deleted file mode 100644 index 7335558b29..0000000000 --- a/.changeset/rude-shrimps-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -This update adds the @backstage/repo-tools package to the versions.ts file, enabling proper version resolution for templates. The {{version '@backstage/repo-tools'}} placeholder now works as expected in the create-app process. diff --git a/.changeset/selfish-ads-count.md b/.changeset/selfish-ads-count.md deleted file mode 100644 index 2f2f0597dd..0000000000 --- a/.changeset/selfish-ads-count.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -The `mockServices.discovery.factory()` factory now uses the mocked discovery service as its implementation, avoid the need for configuration. diff --git a/.changeset/selfish-dots-attend.md b/.changeset/selfish-dots-attend.md deleted file mode 100644 index d11d3003f1..0000000000 --- a/.changeset/selfish-dots-attend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-gitlab': patch ---- - -Removed circular import diff --git a/.changeset/selfish-spies-cough.md b/.changeset/selfish-spies-cough.md deleted file mode 100644 index f702699080..0000000000 --- a/.changeset/selfish-spies-cough.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Disabling database migrations now correctly uses the `backend.default.skipMigrations` config value. diff --git a/.changeset/serious-penguins-remain.md b/.changeset/serious-penguins-remain.md deleted file mode 100644 index fc90b4ad01..0000000000 --- a/.changeset/serious-penguins-remain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog': minor ---- - -Allow `OffsetPaginatedCatalogTable` to configure Table options and `CursorPaginatedCatalogTable` to configure `paginationPosition`. diff --git a/.changeset/seven-berries-listen.md b/.changeset/seven-berries-listen.md deleted file mode 100644 index 2ab18d9e19..0000000000 --- a/.changeset/seven-berries-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': minor ---- - -The package packing now populates `typesVersions` for additional entry points rather than using additional `package.json` files for type resolution. This improves auto completion of separate entry points when consuming published packages. diff --git a/.changeset/seven-bulldogs-count.md b/.changeset/seven-bulldogs-count.md new file mode 100644 index 0000000000..9fa888767b --- /dev/null +++ b/.changeset/seven-bulldogs-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Add support for `--output-file` option from ESLint to `package lint` and `repo lint` commands. diff --git a/.changeset/seven-hotels-move.md b/.changeset/seven-hotels-move.md deleted file mode 100644 index 03bb39116a..0000000000 --- a/.changeset/seven-hotels-move.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-events-backend-module-github': patch ---- - -Fix the event request validation for incoming requests for GitHub webhook events -by using the raw body when verifying the signature. diff --git a/.changeset/shiny-falcons-fly.md b/.changeset/shiny-falcons-fly.md deleted file mode 100644 index 899bbfbda4..0000000000 --- a/.changeset/shiny-falcons-fly.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@backstage/plugin-events-node': patch -'@backstage/plugin-events-backend-module-github': patch -'@backstage/plugin-events-backend': patch ---- - -Add raw body information to `RequestDetails` -and use the raw body when validating incoming event requests. diff --git a/.changeset/short-baboons-search.md b/.changeset/short-baboons-search.md new file mode 100644 index 0000000000..9855ad6df7 --- /dev/null +++ b/.changeset/short-baboons-search.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': minor +--- + +All middleware used by the default `coreServices.http` is now exported for use by custom implementations. diff --git a/.changeset/short-geckos-sniff.md b/.changeset/short-geckos-sniff.md deleted file mode 100644 index 4d31ca436b..0000000000 --- a/.changeset/short-geckos-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue with the `repo lint` command where the cache key for the `--successCache` option would not properly ignore files that should be ignored according to `.eslintignore`s. diff --git a/.changeset/short-pots-remember.md b/.changeset/short-pots-remember.md deleted file mode 100644 index 9a30bc222c..0000000000 --- a/.changeset/short-pots-remember.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Fixed an issue where entities would not be marked for restitching if only the target of a relationship changed. diff --git a/.changeset/shy-clouds-brake.md b/.changeset/shy-clouds-brake.md deleted file mode 100644 index 1e69a1d193..0000000000 --- a/.changeset/shy-clouds-brake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': minor ---- - -Bumped the `isolated-vm` dependency from v4 to v5, which drops support for Node.js v16. diff --git a/.changeset/shy-pots-speak.md b/.changeset/shy-pots-speak.md deleted file mode 100644 index 8eceacb9ec..0000000000 --- a/.changeset/shy-pots-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-test-utils': patch ---- - -Removed unused `msw` dependency. diff --git a/.changeset/shy-rats-hear.md b/.changeset/shy-rats-hear.md deleted file mode 100644 index 460d70c56a..0000000000 --- a/.changeset/shy-rats-hear.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Link to proper package in `rootLoggerServiceFactory` doc string. diff --git a/.changeset/shy-teachers-count.md b/.changeset/shy-teachers-count.md new file mode 100644 index 0000000000..7723fe377b --- /dev/null +++ b/.changeset/shy-teachers-count.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend-module-gitlab': minor +--- + +**BREAKING**: Upgraded the `gitbeaker` library to version 41. As part of this, the `scopes` parameter to the `gitlab:projectDeployToken:create` is no longer optional, so you will have to pass it a value (for example `['read_repository']`). diff --git a/.changeset/silent-pigs-collect.md b/.changeset/silent-pigs-collect.md new file mode 100644 index 0000000000..9010605ffb --- /dev/null +++ b/.changeset/silent-pigs-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-search-backend-node': patch +--- + +Removed unnecessary dependency on `@backstage/backend-defaults`. diff --git a/.changeset/silent-wasps-whisper.md b/.changeset/silent-wasps-whisper.md deleted file mode 100644 index 33620139e7..0000000000 --- a/.changeset/silent-wasps-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder': patch ---- - -Revert the change of the option label for `EntityPicker` diff --git a/.changeset/silly-kiwis-destroy.md b/.changeset/silly-kiwis-destroy.md deleted file mode 100644 index 31bdf4560b..0000000000 --- a/.changeset/silly-kiwis-destroy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-events-backend': patch ---- - -Cleaning up event subscriptions after the max age window diff --git a/.changeset/silver-actors-care.md b/.changeset/silver-actors-care.md new file mode 100644 index 0000000000..5391a1d57b --- /dev/null +++ b/.changeset/silver-actors-care.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fixed an issue where `` would re-render its children on page load for smaller screens, potentially leading to unnecessary additional backend requests. diff --git a/.changeset/silver-ears-grin.md b/.changeset/silver-ears-grin.md deleted file mode 100644 index 104c18719e..0000000000 --- a/.changeset/silver-ears-grin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': minor ---- - -`backstage-repo-tools package schema openapi generate --server` now generates complete TS interfaces for all request/response objects in your OpenAPI schema. This fixes an edge case around recursive schemas and standardizes both the generated client and server to have similar generated types. diff --git a/.changeset/silver-kings-sort.md b/.changeset/silver-kings-sort.md deleted file mode 100644 index b59f70c401..0000000000 --- a/.changeset/silver-kings-sort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-gitlab': minor ---- - -Extended the configuration with the `includeArchivedRepos` property, which allows including repositories when the project is archived. diff --git a/.changeset/six-beds-exercise.md b/.changeset/six-beds-exercise.md deleted file mode 100644 index b2c01e8ac7..0000000000 --- a/.changeset/six-beds-exercise.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-defaults': patch ---- - -Use `node-fetch` instead of native fetch, as per https://backstage.io/docs/architecture-decisions/adrs-adr013 diff --git a/.changeset/six-eels-add.md b/.changeset/six-eels-add.md new file mode 100644 index 0000000000..fa0481b757 --- /dev/null +++ b/.changeset/six-eels-add.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Remove backend-common package from incremental-ingestion plugin and update related code diff --git a/.changeset/sixty-shirts-rescue.md b/.changeset/sixty-shirts-rescue.md new file mode 100644 index 0000000000..b6c1443eea --- /dev/null +++ b/.changeset/sixty-shirts-rescue.md @@ -0,0 +1,41 @@ +--- +'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch +'@backstage/plugin-auth-backend-module-bitbucket-server-provider': patch +'@backstage/plugin-search-backend-module-stack-overflow-collator': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch +'@backstage/plugin-catalog-backend-module-bitbucket-server': patch +'@backstage/plugin-auth-backend-module-microsoft-provider': patch +'@backstage/plugin-auth-backend-module-aws-alb-provider': patch +'@backstage/plugin-scaffolder-backend-module-bitbucket': patch +'@backstage/plugin-scaffolder-backend-module-gerrit': patch +'@backstage/plugin-scaffolder-backend-module-sentry': patch +'@backstage/plugin-catalog-backend-module-puppetdb': patch +'@backstage/plugin-scaffolder-backend-module-gitea': patch +'@backstage/plugin-catalog-backend-module-msgraph': patch +'@backstage/plugin-search-backend-module-techdocs': patch +'@backstage/plugin-catalog-backend-module-gerrit': patch +'@backstage/plugin-catalog-backend-module-gitlab': patch +'@backstage/plugin-search-backend-module-explore': patch +'@backstage/plugin-catalog-backend-module-azure': patch +'@backstage/plugin-notifications-backend': patch +'@backstage/plugin-notifications-node': patch +'@backstage/plugin-permission-backend': patch +'@backstage/backend-app-api': patch +'@backstage/plugin-devtools-backend': patch +'@backstage/plugin-techdocs-backend': patch +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-signals-backend': patch +'@backstage/config-loader': patch +'@backstage/plugin-proxy-backend': patch +'@backstage/plugin-auth-backend': patch +'@backstage/create-app': patch +'@backstage/plugin-app-backend': patch +'@backstage/plugin-auth-node': patch +'@backstage/cli': patch +'@backstage/backend-defaults': patch +'@backstage/plugin-catalog-backend-module-github': patch +'@backstage/plugin-scaffolder-backend-module-confluence-to-markdown': patch +--- + +Use native fetch instead of node-fetch diff --git a/.changeset/slimy-jobs-scream.md b/.changeset/slimy-jobs-scream.md deleted file mode 100644 index e20119fed4..0000000000 --- a/.changeset/slimy-jobs-scream.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-techdocs-react': patch -'@backstage/plugin-techdocs': patch ---- - -Fix an issue that caused the current documentation page to be re-rendered when navigating to -another one. diff --git a/.changeset/slimy-penguins-care.md b/.changeset/slimy-penguins-care.md deleted file mode 100644 index 96016b1ba4..0000000000 --- a/.changeset/slimy-penguins-care.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fix for the `--link` flag for `package start` to deduplicate `react-router` and `react-router-dom`. diff --git a/.changeset/slow-horses-destroy.md b/.changeset/slow-horses-destroy.md new file mode 100644 index 0000000000..fe23d6cf27 --- /dev/null +++ b/.changeset/slow-horses-destroy.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +'@backstage/plugin-kubernetes-backend': patch +--- + +Create a `dev/index.ts` entrypoint for `yarn start` diff --git a/.changeset/slow-mayflies-sleep.md b/.changeset/slow-mayflies-sleep.md deleted file mode 100644 index ebfb9d12d4..0000000000 --- a/.changeset/slow-mayflies-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': minor ---- - -Adds a `--watch` mode to the `schema openapi generate` command for a better local schema writing experience. diff --git a/.changeset/slow-shrimps-call.md b/.changeset/slow-shrimps-call.md deleted file mode 100644 index 7e04633307..0000000000 --- a/.changeset/slow-shrimps-call.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/plugin-notifications-backend': patch -'@backstage/plugin-notifications-common': patch -'@backstage/plugin-notifications': patch ---- - -Add support for user specific notification settings diff --git a/.changeset/slow-singers-jump.md b/.changeset/slow-singers-jump.md new file mode 100644 index 0000000000..2eef032d7b --- /dev/null +++ b/.changeset/slow-singers-jump.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': minor +--- + +Fetch all facets in a single database query diff --git a/.changeset/small-boxes-enjoy.md b/.changeset/small-boxes-enjoy.md new file mode 100644 index 0000000000..819e247d49 --- /dev/null +++ b/.changeset/small-boxes-enjoy.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +When parsing filters, do not make redundant `anyOf` and `allOf` nodes when there's only a single entry within them diff --git a/.changeset/smart-bags-sell.md b/.changeset/smart-bags-sell.md deleted file mode 100644 index 2c5f5c4d87..0000000000 --- a/.changeset/smart-bags-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-app-visualizer': patch ---- - -New `devDependency` for local development setup. diff --git a/.changeset/smart-islands-judge.md b/.changeset/smart-islands-judge.md new file mode 100644 index 0000000000..8b21666c4c --- /dev/null +++ b/.changeset/smart-islands-judge.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder-react': patch +'@backstage/plugin-scaffolder': patch +--- + +Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder. diff --git a/.changeset/smooth-bikes-sparkle.md b/.changeset/smooth-bikes-sparkle.md new file mode 100644 index 0000000000..0c1eba172b --- /dev/null +++ b/.changeset/smooth-bikes-sparkle.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': minor +--- + +Implemented discovery for top-level groups defined in config.group or if undefined global top-level group in Gitlab diff --git a/.changeset/soft-turkeys-tie.md b/.changeset/soft-turkeys-tie.md deleted file mode 100644 index 3962f49460..0000000000 --- a/.changeset/soft-turkeys-tie.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Modified `createDryRunner` and corresponding route to include `templateMetaData` inside the `templateInfo`. This allows custom action writers to access things like `templateInfo.entity.metadata.name` via the action context while executing templates using the dry run framework. diff --git a/.changeset/spotty-shoes-exercise.md b/.changeset/spotty-shoes-exercise.md new file mode 100644 index 0000000000..92e0825c9f --- /dev/null +++ b/.changeset/spotty-shoes-exercise.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Support changing location keys on existing entities, in delta mutations diff --git a/.changeset/spotty-snails-worry.md b/.changeset/spotty-snails-worry.md deleted file mode 100644 index 3ecf2e9b35..0000000000 --- a/.changeset/spotty-snails-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-signals-backend': patch ---- - -The signals backend now supports scaled deployments where clients may be connecting to one of many signal backend instances. diff --git a/.changeset/stale-hats-exist.md b/.changeset/stale-hats-exist.md new file mode 100644 index 0000000000..227656cd5b --- /dev/null +++ b/.changeset/stale-hats-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Avoid extra ordering in by-query when the user doesn't ask for it diff --git a/.changeset/stale-rats-tease.md b/.changeset/stale-rats-tease.md new file mode 100644 index 0000000000..3564742cc6 --- /dev/null +++ b/.changeset/stale-rats-tease.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-google-provider': patch +--- + +Pass through `includeGrantedScopes` in order to persist scopes across refresh calls diff --git a/.changeset/strange-brooms-check.md b/.changeset/strange-brooms-check.md new file mode 100644 index 0000000000..b6cb897170 --- /dev/null +++ b/.changeset/strange-brooms-check.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Fixed an issue where the `EntityOwnerPicker` component failed to load when the `mode` prop was set to `owners-only`. In this mode, the `EntityOwnerPicker` does not load details about the owners, such as `displayName` or `title`. To display these details, use `mode=all` instead. diff --git a/.changeset/strange-clocks-pretend.md b/.changeset/strange-clocks-pretend.md deleted file mode 100644 index 9a3b6e20ac..0000000000 --- a/.changeset/strange-clocks-pretend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -The `generate-patch` command will now fall back to always adding a `resolutions` entry, even if no matching descriptors are found. diff --git a/.changeset/strong-papayas-remember.md b/.changeset/strong-papayas-remember.md new file mode 100644 index 0000000000..7787258c58 --- /dev/null +++ b/.changeset/strong-papayas-remember.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Fix link styling in ProvidedApisCard component so it aligns with other card components. diff --git a/.changeset/strong-paws-change.md b/.changeset/strong-paws-change.md deleted file mode 100644 index 9ac6c06993..0000000000 --- a/.changeset/strong-paws-change.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/create-app': patch ---- - -Use the main entrypoint for `create-app` installs diff --git a/.changeset/stupid-crabs-wash.md b/.changeset/stupid-crabs-wash.md new file mode 100644 index 0000000000..d9e7f317df --- /dev/null +++ b/.changeset/stupid-crabs-wash.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +--- + +Support fetch pod metrics with custom resources diff --git a/.changeset/swift-kangaroos-drop.md b/.changeset/swift-kangaroos-drop.md new file mode 100644 index 0000000000..77d837deba --- /dev/null +++ b/.changeset/swift-kangaroos-drop.md @@ -0,0 +1,5 @@ +--- +'@backstage/catalog-client': patch +--- + +Fixed a bug in the `queryEntities` method where errors were not being handled properly. diff --git a/.changeset/swift-laws-applaud.md b/.changeset/swift-laws-applaud.md deleted file mode 100644 index 8de93e825b..0000000000 --- a/.changeset/swift-laws-applaud.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Update upgrade-helper link in `versions:bump` command to include `yarnPlugin` parameter when the yarn plugin is installed diff --git a/.changeset/tall-comics-heal.md b/.changeset/tall-comics-heal.md new file mode 100644 index 0000000000..3d65caee67 --- /dev/null +++ b/.changeset/tall-comics-heal.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-azure': minor +--- + +Added the Azure Blob Storage as catalog entity provider to import all the desired entities from storage account provided in app-config.yaml diff --git a/.changeset/ten-cars-end.md b/.changeset/ten-cars-end.md new file mode 100644 index 0000000000..66d13fd8a2 --- /dev/null +++ b/.changeset/ten-cars-end.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +added experimental RSPack support for build command in the repo scope diff --git a/.changeset/ten-hats-appear.md b/.changeset/ten-hats-appear.md deleted file mode 100644 index 318bbfbb25..0000000000 --- a/.changeset/ten-hats-appear.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@backstage/plugin-scaffolder-react': minor -'@backstage/plugin-scaffolder': minor ---- - -Fix `contextMenu` not being disabled bug in new scaffolder pages diff --git a/.changeset/ten-keys-nail.md b/.changeset/ten-keys-nail.md new file mode 100644 index 0000000000..0662e4a346 --- /dev/null +++ b/.changeset/ten-keys-nail.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-defaults': patch +--- + +Fixed an issue in the WinstonLogger where Errors thrown and given to logger.error with field values that could not be cast to a string would throw a TypeError diff --git a/.changeset/ten-pears-unite.md b/.changeset/ten-pears-unite.md deleted file mode 100644 index 75f7e2cc22..0000000000 --- a/.changeset/ten-pears-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-openapi-utils': minor ---- - -Adds a new `createValidatedOpenApiRouterFromGeneratedEndpointMap` function that uses the new static server generation in `backstage-cli package schema openapi generate --server` to create a typed express router. diff --git a/.changeset/tender-feet-scream.md b/.changeset/tender-feet-scream.md deleted file mode 100644 index b8ed5dd792..0000000000 --- a/.changeset/tender-feet-scream.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Added `entity_ref` column to `final_entities` in order to move `refresh_state` away from the read path diff --git a/.changeset/thick-items-bathe.md b/.changeset/thick-items-bathe.md new file mode 100644 index 0000000000..455718ed1c --- /dev/null +++ b/.changeset/thick-items-bathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Added data-testid to placeholder rendered by Progress component to simplify assertions in tests diff --git a/.changeset/thick-rice-hunt.md b/.changeset/thick-rice-hunt.md deleted file mode 100644 index ac1ee64f3b..0000000000 --- a/.changeset/thick-rice-hunt.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -'@backstage/plugin-auth-backend-module-cloudflare-access-provider': patch -'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch -'@backstage/plugin-catalog-backend-module-backstage-openapi': patch -'@backstage/plugin-catalog-backend-module-bitbucket-server': patch -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch -'@backstage/plugin-search-backend-module-elasticsearch': patch -'@backstage/plugin-catalog-backend-module-puppetdb': patch -'@backstage/plugin-catalog-backend-module-msgraph': patch -'@backstage/plugin-catalog-backend-module-gerrit': patch -'@backstage/plugin-catalog-backend-module-github': patch -'@backstage/plugin-catalog-backend-module-gitlab': patch -'@backstage/plugin-catalog-backend-module-azure': patch -'@backstage/plugin-catalog-backend-module-ldap': patch -'@backstage/plugin-catalog-backend-module-aws': patch -'@backstage/plugin-search-backend-module-pg': patch -'@backstage/plugin-notifications-backend': patch -'@backstage/backend-test-utils': patch -'@backstage/plugin-search-backend-node': patch -'@backstage/plugin-notifications-node': patch -'@backstage/plugin-scaffolder-backend': patch -'@backstage/backend-defaults': patch -'@backstage/plugin-permission-common': patch -'@backstage/backend-app-api': patch -'@backstage/plugin-catalog-backend': patch -'@backstage/plugin-signals-backend': patch -'@backstage/plugin-proxy-backend': patch -'@backstage/plugin-auth-backend': patch -'@backstage/plugin-signals-node': patch -'@backstage/plugin-auth-node': patch -'@backstage/plugin-signals': patch ---- - -Upgrade to uuid v11 internally diff --git a/.changeset/thick-trees-worry.md b/.changeset/thick-trees-worry.md deleted file mode 100644 index 7f5428f739..0000000000 --- a/.changeset/thick-trees-worry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Fixed an issue where `.css` style injection would fail for published packages. diff --git a/.changeset/thin-hotels-explode.md b/.changeset/thin-hotels-explode.md new file mode 100644 index 0000000000..f06b512cc5 --- /dev/null +++ b/.changeset/thin-hotels-explode.md @@ -0,0 +1,5 @@ +--- +'@backstage/errors': patch +--- + +Trim `error.cause.stack` in addition to `error.stack` when trimming stack traces from serialized errors. diff --git a/.changeset/three-mangos-dance.md b/.changeset/three-mangos-dance.md deleted file mode 100644 index 0135869611..0000000000 --- a/.changeset/three-mangos-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/backend-openapi-utils': patch ---- - -Moves msw from dependencies to devDependencies diff --git a/.changeset/tiny-mice-run.md b/.changeset/tiny-mice-run.md new file mode 100644 index 0000000000..4829ef7390 --- /dev/null +++ b/.changeset/tiny-mice-run.md @@ -0,0 +1,5 @@ +--- +'@backstage/repo-tools': patch +--- + +The `generate-patch` command will now add a single resolution entry for all versions of the patched package, rather than separate entries for each version query. diff --git a/.changeset/tough-onions-dance.md b/.changeset/tough-onions-dance.md deleted file mode 100644 index 46b7477399..0000000000 --- a/.changeset/tough-onions-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/repo-tools': patch ---- - -Added a new `generate-patch` command that can be used to generate patches for current changes in a source workspace to be installed it a target workspace. diff --git a/.changeset/tricky-crabs-lick.md b/.changeset/tricky-crabs-lick.md deleted file mode 100644 index 4f858538a3..0000000000 --- a/.changeset/tricky-crabs-lick.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-bitbucket-server': patch -'@backstage/plugin-scaffolder-backend-module-bitbucket-cloud': patch ---- - -Fix double branch creation in `public:bitbucket{Cloud,Server}:pull-request` -This resulted in the following error when using the actions: - -``` -AlreadyExistsError: Failed to create branch at create-test because it already exists. -``` - -The issue was original introduced in d103a48fa306d745599dc0c793668c9e6a479d32 diff --git a/.changeset/twelve-masks-call.md b/.changeset/twelve-masks-call.md deleted file mode 100644 index 7fc79db655..0000000000 --- a/.changeset/twelve-masks-call.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': minor ---- - -Drop redundant indices from the database. - -The following redundant indices are removed in this version: - -- `final_entities_entity_id_idx` - overlaps with `final_entities_pkey` -- `refresh_state_entity_id_idx` - overlaps with `refresh_state_pkey` -- `refresh_state_entity_ref_idx` - overlaps with `refresh_state_entity_ref_uniq` -- `search_key_idx` and `search_value_idx` - these were replaced by the composite index `search_key_value_idx` in #22594 - -No negative end user impact is expected, but rather that performance should increase due to less index churn. diff --git a/.changeset/twenty-monkeys-applaud.md b/.changeset/twenty-monkeys-applaud.md new file mode 100644 index 0000000000..a1b0c1d338 --- /dev/null +++ b/.changeset/twenty-monkeys-applaud.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Resolved an issue where the `templateManagementPermission` was not being exposed through the `/permissions/metadata` endpoint. diff --git a/.changeset/twenty-parents-judge.md b/.changeset/twenty-parents-judge.md new file mode 100644 index 0000000000..a639f83ba1 --- /dev/null +++ b/.changeset/twenty-parents-judge.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-app-backend': patch +--- + +Fix root route handling when query parameters are present diff --git a/.changeset/two-donuts-float.md b/.changeset/two-donuts-float.md deleted file mode 100644 index d9df082910..0000000000 --- a/.changeset/two-donuts-float.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': patch ---- - -Fix for certain filter fields in the `catalogApiMock` being case sensitive. diff --git a/.changeset/unlucky-countries-shop.md b/.changeset/unlucky-countries-shop.md deleted file mode 100644 index 06c193068b..0000000000 --- a/.changeset/unlucky-countries-shop.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend-module-rails': patch -'@backstage/plugin-kubernetes-cluster': patch -'@techdocs/cli': patch -'@backstage/cli-common': patch -'@backstage/create-app': patch -'@backstage/repo-tools': patch -'@backstage/codemods': patch -'@backstage/cli': patch ---- - -Bumped dev dependencies `@types/node` diff --git a/.changeset/violet-dolphins-juggle.md b/.changeset/violet-dolphins-juggle.md deleted file mode 100644 index e0e75f1481..0000000000 --- a/.changeset/violet-dolphins-juggle.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -'@backstage/plugin-search-backend-module-stack-overflow-collator': patch -'@backstage/plugin-scaffolder-backend-module-notifications': patch -'@backstage/plugin-auth-backend-module-aws-alb-provider': patch -'@backstage/plugin-auth-backend-module-guest-provider': patch -'@backstage/plugin-notifications-backend-module-email': patch -'@backstage/plugin-auth-backend-module-oidc-provider': patch -'@backstage/plugin-scaffolder-backend-module-yeoman': patch -'@backstage/plugin-notifications-node': patch -'@backstage/backend-app-api': patch -'@backstage/plugin-signals-node': patch -'@backstage/plugin-events-node': patch -'@backstage/cli': patch ---- - -Remove unused backend-common dependency diff --git a/.changeset/violet-ears-dance.md b/.changeset/violet-ears-dance.md deleted file mode 100644 index dba3671338..0000000000 --- a/.changeset/violet-ears-dance.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': minor ---- - -**BREAKING**: The `LEGACY_BACKEND_START` flag has been removed, along with support for `src/run.ts` as the development entry point. diff --git a/.changeset/violet-parrots-knock.md b/.changeset/violet-parrots-knock.md deleted file mode 100644 index dde0f9e606..0000000000 --- a/.changeset/violet-parrots-knock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add new `fs:readdir` action to list current content of the workspace diff --git a/.changeset/violet-snakes-laugh.md b/.changeset/violet-snakes-laugh.md new file mode 100644 index 0000000000..7002cfeaf0 --- /dev/null +++ b/.changeset/violet-snakes-laugh.md @@ -0,0 +1,5 @@ +--- +'@backstage/release-manifests': patch +--- + +Allow overriding the fetch function used inside getManifestByVersion diff --git a/.changeset/warm-boats-move.md b/.changeset/warm-boats-move.md deleted file mode 100644 index 2b21e42717..0000000000 --- a/.changeset/warm-boats-move.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend': patch ---- - -Internal refactor to slightly speed up the processing loop diff --git a/.changeset/warm-pumpkins-bathe.md b/.changeset/warm-pumpkins-bathe.md new file mode 100644 index 0000000000..93fa603342 --- /dev/null +++ b/.changeset/warm-pumpkins-bathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-react': patch +--- + +Open links in the scaffolder entity and step descriptions in a new tab, to ensure consistency and improve user experience diff --git a/.changeset/warm-tomatoes-develop.md b/.changeset/warm-tomatoes-develop.md deleted file mode 100644 index 100692f612..0000000000 --- a/.changeset/warm-tomatoes-develop.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/backend-dynamic-feature-service': patch ---- - -Improve the way alpha packages are supported when loading dynamic backend plugins. -The `ScannedPluginPackage` descriptor of dynamic backend plugins loaded from their alpha `package.json` now contain both the main package manifest and the alpha manifest. Previously it used to contain only the content of the alpha `package.json`, which is nearly empty. -This will make it easier to use or display metadata of loaded dynamic backend plugins, which is contained in the main manifest. diff --git a/.changeset/heavy-phones-shave.md b/.changeset/weak-avocados-suffer.md similarity index 64% rename from .changeset/heavy-phones-shave.md rename to .changeset/weak-avocados-suffer.md index 4f268d81ac..01142aa927 100644 --- a/.changeset/heavy-phones-shave.md +++ b/.changeset/weak-avocados-suffer.md @@ -2,4 +2,4 @@ '@backstage/plugin-catalog-backend-module-ldap': minor --- -Add Support for Google LDAP Vendor +Add new ldap vendor config 'LLDAP' diff --git a/.changeset/weak-meals-doubt.md b/.changeset/weak-meals-doubt.md new file mode 100644 index 0000000000..42199ed296 --- /dev/null +++ b/.changeset/weak-meals-doubt.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch +--- + +Ensure that the scheduled worker task doesn't run at an unreasonably high frequency diff --git a/.changeset/wet-rats-exist.md b/.changeset/wet-rats-exist.md new file mode 100644 index 0000000000..08bcc1c28f --- /dev/null +++ b/.changeset/wet-rats-exist.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-app-api': patch +--- + +Decrease OAuth2 token refresh grace period diff --git a/.changeset/wild-experts-unite.md b/.changeset/wild-experts-unite.md deleted file mode 100644 index 872a3aa8de..0000000000 --- a/.changeset/wild-experts-unite.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Bump the Webpack dependency range to `^5.94.0`, as our current configuration is not compatible with some older versions. diff --git a/.changeset/wise-avocados-behave.md b/.changeset/wise-avocados-behave.md deleted file mode 100644 index 5d26ec0066..0000000000 --- a/.changeset/wise-avocados-behave.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added support for `.webp` files in the frontend tooling. diff --git a/.changeset/wise-snakes-sleep.md b/.changeset/wise-snakes-sleep.md deleted file mode 100644 index ca51972f57..0000000000 --- a/.changeset/wise-snakes-sleep.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-backend-module-bitbucket-cloud': patch ---- - -Implemented discovery on project-level to shift Bitbucket Cloud API limits diff --git a/.changeset/witty-bobcats-push.md b/.changeset/witty-bobcats-push.md deleted file mode 100644 index c2b357a860..0000000000 --- a/.changeset/witty-bobcats-push.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-scaffolder-backend': patch ---- - -Add example template for notification sending diff --git a/.changeset/witty-socks-repeat.md b/.changeset/witty-socks-repeat.md deleted file mode 100644 index bbac3d9a88..0000000000 --- a/.changeset/witty-socks-repeat.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@backstage/cli': patch ---- - -Added a new `--link ` option for frontend builds that allow you to override module resolution to link in an external workspace at runtime. - -As part of this change the Webpack linked workspace resolution plugin for frontend builds has been removed. It was in place to support the old workspace linking where it was done by Yarn, which is no longer a working option. diff --git a/.changeset/yellow-horses-pretend.md b/.changeset/yellow-horses-pretend.md deleted file mode 100644 index 3171993d2a..0000000000 --- a/.changeset/yellow-horses-pretend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-events-node': patch ---- - -Fixed an issue where the event bus polling would duplicate and increase exponentially over time. diff --git a/.changeset/young-carrots-collect.md b/.changeset/young-carrots-collect.md new file mode 100644 index 0000000000..1350400d39 --- /dev/null +++ b/.changeset/young-carrots-collect.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend': patch +--- + +Compute some metrics using search table facet aggregations instead of reading the full refresh state diff --git a/.changeset/young-cobras-add.md b/.changeset/young-cobras-add.md new file mode 100644 index 0000000000..f9172d3800 --- /dev/null +++ b/.changeset/young-cobras-add.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-app-api': patch +--- + +As soon as a backend termination signal is received, call before shutting down root lifecycle hooks. diff --git a/.changeset/young-months-admire.md b/.changeset/young-months-admire.md new file mode 100644 index 0000000000..a2062b3f88 --- /dev/null +++ b/.changeset/young-months-admire.md @@ -0,0 +1,6 @@ +--- +'@backstage/backend-app-api': minor +'@backstage/backend-plugin-api': minor +--- + +**EXPERIMENTAL**: Adds a new `instanceMetadataService` to hold information about a specific backend instance. diff --git a/.changeset/young-penguins-act.md b/.changeset/young-penguins-act.md deleted file mode 100644 index bae2fe089f..0000000000 --- a/.changeset/young-penguins-act.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/catalog-client': minor ---- - -The client now automatically splits up very large `getEntitiesByRefs` calls into several smaller requests behind the scenes when needed. This ensures that each individual request does not exceed common Express.js request body limits or overload the server. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c7326c5f4e..b31cca1080 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,10 +12,12 @@ yarn.lock @backstage/maintainers @backst /docs @backstage/maintainers @backstage/documentation-maintainers /docs/assets/search @backstage/search-maintainers /docs/features/search @backstage/search-maintainers +/docs/dls @backstage/design-system-maintainers /docs/features/techdocs @backstage/techdocs-maintainers /docs/plugins/integrating-search-into-plugins.md @backstage/search-maintainers /packages/cli/src/commands/onboard @backstage/sharks /packages/backend-openapi-utils @backstage/maintainers @backstage/reviewers @backstage/openapi-tooling-maintainers +/packages/canon @backstage/design-system-maintainers /packages/techdocs-cli @backstage/techdocs-maintainers /packages/techdocs-cli-embedded-app @backstage/techdocs-maintainers /plugins/api-docs @backstage/maintainers @backstage/reviewers @backstage/sda-se-reviewers diff --git a/.github/vale/config/vocabularies/Backstage/accept.txt b/.github/vale/config/vocabularies/Backstage/accept.txt index a015b97a32..fc0fd5021e 100644 --- a/.github/vale/config/vocabularies/Backstage/accept.txt +++ b/.github/vale/config/vocabularies/Backstage/accept.txt @@ -80,6 +80,8 @@ cron cronjobs crontab css +cve +CVEs daemonsets Datadog dataflow @@ -95,12 +97,15 @@ deliverables denormalized dependabot deps +deserialization destructured destructuring Deutsche dev devops devs +dequeue +dequeueing dialogs discoverability Discoverability @@ -337,6 +342,7 @@ rebase rebasing Recharts Redash +redis renderer renderers replicasets diff --git a/.github/workflows/api-breaking-changes-comment.yml b/.github/workflows/api-breaking-changes-comment.yml index 15b13810f5..1210db0ccf 100644 --- a/.github/workflows/api-breaking-changes-comment.yml +++ b/.github/workflows/api-breaking-changes-comment.yml @@ -22,7 +22,7 @@ jobs: action: ${{ steps.event.outputs.ACTION }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: disable-sudo: true egress-policy: block diff --git a/.github/workflows/api-breaking-changes.yml b/.github/workflows/api-breaking-changes.yml index a6ba0e393b..744c9e62c3 100644 --- a/.github/workflows/api-breaking-changes.yml +++ b/.github/workflows/api-breaking-changes.yml @@ -14,7 +14,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.action != 'closed' }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -33,7 +33,7 @@ jobs: registry-url: https://registry.npmjs.org/ - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: linux-v20 diff --git a/.github/workflows/automate_area-labels.yml b/.github/workflows/automate_area-labels.yml index 89e1adc3c3..4529b54c16 100644 --- a/.github/workflows/automate_area-labels.yml +++ b/.github/workflows/automate_area-labels.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/automate_changeset_feedback.yml b/.github/workflows/automate_changeset_feedback.yml index d7e2b56b39..1a29795cce 100644 --- a/.github/workflows/automate_changeset_feedback.yml +++ b/.github/workflows/automate_changeset_feedback.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -34,7 +34,7 @@ jobs: ref: 'refs/pull/${{ github.event.pull_request.number }}/merge' - name: fetch base run: git fetch --depth 1 origin ${{ github.base_ref }} - - uses: backstage/actions/changeset-feedback@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + - uses: backstage/actions/changeset-feedback@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 name: Generate feedback with: diff-ref: 'origin/master' diff --git a/.github/workflows/automate_merge_message.yml b/.github/workflows/automate_merge_message.yml index ece1331730..7923496b3f 100644 --- a/.github/workflows/automate_merge_message.yml +++ b/.github/workflows/automate_merge_message.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/automate_stale.yml b/.github/workflows/automate_stale.yml index b7adc5235a..e61ca20620 100644 --- a/.github/workflows/automate_stale.yml +++ b/.github/workflows/automate_stale.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/ci-noop.yml b/.github/workflows/ci-noop.yml index af7199ede6..a769ce7d50 100644 --- a/.github/workflows/ci-noop.yml +++ b/.github/workflows/ci-noop.yml @@ -40,7 +40,7 @@ jobs: name: Test ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a959b7aa9a..24e74ff0f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: name: Install ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -41,7 +41,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -64,7 +64,7 @@ jobs: name: Verify ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -77,7 +77,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -225,7 +225,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml index 48ac1db289..5961a9155f 100644 --- a/.github/workflows/cron.yml +++ b/.github/workflows/cron.yml @@ -10,11 +10,11 @@ jobs: timeout-minutes: 10 steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - - uses: backstage/actions/cron@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + - uses: backstage/actions/cron@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/deploy_docker-image.yml b/.github/workflows/deploy_docker-image.yml index f0d8d0048d..a7ac58b76a 100644 --- a/.github/workflows/deploy_docker-image.yml +++ b/.github/workflows/deploy_docker-image.yml @@ -20,7 +20,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -37,7 +37,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/deploy_microsite.yml b/.github/workflows/deploy_microsite.yml index 9fe2728256..1f18c6ed15 100644 --- a/.github/workflows/deploy_microsite.yml +++ b/.github/workflows/deploy_microsite.yml @@ -23,7 +23,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -65,7 +65,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v20.x @@ -91,7 +91,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -105,7 +105,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v20.x @@ -158,7 +158,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/deploy_packages.yml b/.github/workflows/deploy_packages.yml index b95a6f9341..c66206ca8d 100644 --- a/.github/workflows/deploy_packages.yml +++ b/.github/workflows/deploy_packages.yml @@ -76,7 +76,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} @@ -147,7 +147,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/issue.yaml b/.github/workflows/issue.yaml index 2cd355b75e..c10f248f6d 100644 --- a/.github/workflows/issue.yaml +++ b/.github/workflows/issue.yaml @@ -16,7 +16,7 @@ jobs: if: github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment-trigger.yaml b/.github/workflows/pr-review-comment-trigger.yaml index 9ebfbee3b0..b5027d78be 100644 --- a/.github/workflows/pr-review-comment-trigger.yaml +++ b/.github/workflows/pr-review-comment-trigger.yaml @@ -20,7 +20,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/pr-review-comment.yaml b/.github/workflows/pr-review-comment.yaml index 517a978a83..18c39ebbd1 100644 --- a/.github/workflows/pr-review-comment.yaml +++ b/.github/workflows/pr-review-comment.yaml @@ -17,7 +17,7 @@ jobs: steps: # Inspired by https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#using-data-from-the-triggering-workflow - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -40,7 +40,7 @@ jobs: const prNumber = artifact.name.slice('pr_number-'.length) core.setOutput('pr-number', prNumber); - - uses: backstage/actions/re-review@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + - uses: backstage/actions/re-review@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} private-key: ${{ secrets.BACKSTAGE_GOALIE_PRIVATE_KEY }} diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 7639ac14db..5b8673858b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -18,12 +18,12 @@ jobs: if: github.repository == 'backstage/backstage' && ( github.event.pull_request || github.event.issue.pull_request ) steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit - name: PR sync - uses: backstage/actions/pr-sync@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/pr-sync@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: github-token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} app-id: ${{ secrets.BACKSTAGE_GOALIE_APPLICATION_ID }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a1c643377d..a40c5a0653 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -67,6 +67,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: 'Upload to code-scanning' - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: results.sarif diff --git a/.github/workflows/sync_canon.yml b/.github/workflows/sync_canon.yml new file mode 100644 index 0000000000..189e43215e --- /dev/null +++ b/.github/workflows/sync_canon.yml @@ -0,0 +1,56 @@ +name: Sync Canon Storybook +on: + push: + branches: [master] + +jobs: + sync-canon-storybook: + runs-on: ubuntu-latest + steps: + - name: Harden Runner + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Use Node.js 20.x + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 + with: + node-version: 20.x + registry-url: https://registry.npmjs.org/ # Needed for auth + + - name: yarn install + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 + with: + cache-prefix: ${{ runner.os }}-v20.x + + - name: Checkout backstage/canon-storybook + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + repository: backstage/canon-storybook + path: canon-storybook + token: ${{ secrets.GH_SERVICE_ACCOUNT_TOKEN }} + + - name: Configure Git + run: | + git config --global user.email noreply@backstage.io + git config --global user.name 'Github Canon Storybook workflow' + + - name: Build Canon Storybook + run: | + yarn workspace @backstage/canon run build-storybook + + - name: Replace contents of canon-storybook repo with Storybook build output + working-directory: canon-storybook + run: | + git rm -rf . + cp -R ../packages/canon/storybook-static/. . + + - name: Commit to canon-storybook repo + working-directory: canon-storybook + run: | + git add . + git commit -am "Canon Storybook build for backstage/backstage@${{ github.sha }}" + git push diff --git a/.github/workflows/sync_code-formatting.yml b/.github/workflows/sync_code-formatting.yml index 4de42669e4..6658f8b850 100644 --- a/.github/workflows/sync_code-formatting.yml +++ b/.github/workflows/sync_code-formatting.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -25,7 +25,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/sync_dependabot-changesets.yml b/.github/workflows/sync_dependabot-changesets.yml index 31db319229..2c2d5a51d0 100644 --- a/.github/workflows/sync_dependabot-changesets.yml +++ b/.github/workflows/sync_dependabot-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'dependabot[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/sync_release-manifest.yml b/.github/workflows/sync_release-manifest.yml index f2f9e1d819..d4fe6e2fa0 100644 --- a/.github/workflows/sync_release-manifest.yml +++ b/.github/workflows/sync_release-manifest.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -25,7 +25,7 @@ jobs: registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v20.x diff --git a/.github/workflows/sync_renovate-changesets.yml b/.github/workflows/sync_renovate-changesets.yml index 9331dbdb05..e4d60777cd 100644 --- a/.github/workflows/sync_renovate-changesets.yml +++ b/.github/workflows/sync_renovate-changesets.yml @@ -11,7 +11,7 @@ jobs: if: github.actor == 'renovate[bot]' && github.repository == 'backstage/backstage' steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/sync_snyk-github-issues.yml b/.github/workflows/sync_snyk-github-issues.yml index 20d4f0f144..9084593052 100644 --- a/.github/workflows/sync_snyk-github-issues.yml +++ b/.github/workflows/sync_snyk-github-issues.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -24,7 +24,7 @@ jobs: node-version: 20.x registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v20.x diff --git a/.github/workflows/sync_snyk-monitor.yml b/.github/workflows/sync_snyk-monitor.yml index c3bdb9b647..6300b1ca4d 100644 --- a/.github/workflows/sync_snyk-monitor.yml +++ b/.github/workflows/sync_snyk-monitor.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -58,6 +58,6 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} NODE_OPTIONS: --max-old-space-size=7168 - name: Upload Snyk report - uses: github/codeql-action/upload-sarif@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/upload-sarif@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: sarif_file: snyk.sarif diff --git a/.github/workflows/sync_version-packages.yml b/.github/workflows/sync_version-packages.yml index 970a5e0e3f..479f65a53a 100644 --- a/.github/workflows/sync_version-packages.yml +++ b/.github/workflows/sync_version-packages.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility-noop.yml b/.github/workflows/verify_accessibility-noop.yml index 37ce3513e9..9af85ec2d1 100644 --- a/.github/workflows/verify_accessibility-noop.yml +++ b/.github/workflows/verify_accessibility-noop.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_accessibility.yml b/.github/workflows/verify_accessibility.yml index 41d549cc7a..1c326bc880 100644 --- a/.github/workflows/verify_accessibility.yml +++ b/.github/workflows/verify_accessibility.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -30,7 +30,7 @@ jobs: with: node-version: 20.x - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v20.x - name: run Lighthouse CI diff --git a/.github/workflows/verify_codeql.yml b/.github/workflows/verify_codeql.yml index af16c5b5af..cb40f28f54 100644 --- a/.github/workflows/verify_codeql.yml +++ b/.github/workflows/verify_codeql.yml @@ -42,7 +42,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -55,7 +55,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/init@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -66,7 +66,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/autobuild@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -80,4 +80,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f779452ac5af1c261dce0346a8f964149f49322b # v3.26.13 + uses: github/codeql-action/analyze@babb554ede22fd5605947329c4d04d8e7a0b8155 # v3.27.7 diff --git a/.github/workflows/verify_docs-quality.yml b/.github/workflows/verify_docs-quality.yml index 766d289f4c..9a93be4090 100644 --- a/.github/workflows/verify_docs-quality.yml +++ b/.github/workflows/verify_docs-quality.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux-noop.yml b/.github/workflows/verify_e2e-linux-noop.yml index 1afcd3fe17..4e3eeb2a8c 100644 --- a/.github/workflows/verify_e2e-linux-noop.yml +++ b/.github/workflows/verify_e2e-linux-noop.yml @@ -29,7 +29,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-linux.yml b/.github/workflows/verify_e2e-linux.yml index 9f3c5ae009..ef24955b0e 100644 --- a/.github/workflows/verify_e2e-linux.yml +++ b/.github/workflows/verify_e2e-linux.yml @@ -8,6 +8,8 @@ on: - 'docs/**' - 'microsite/**' - 'beps/**' + push: + branches: [master] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -41,7 +43,7 @@ jobs: name: E2E Linux ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -58,7 +60,7 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_e2e-techdocs.yml b/.github/workflows/verify_e2e-techdocs.yml index b42cae8896..454c4c011e 100644 --- a/.github/workflows/verify_e2e-techdocs.yml +++ b/.github/workflows/verify_e2e-techdocs.yml @@ -7,6 +7,8 @@ on: - 'packages/techdocs-cli/**' - 'packages/techdocs-cli-embedded-app/**' - 'plugins/techdocs/**' + push: + branches: [master] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -30,7 +32,7 @@ jobs: name: Techdocs steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows-noop.yml b/.github/workflows/verify_e2e-windows-noop.yml index 3e415b82c6..78d4c1e37f 100644 --- a/.github/workflows/verify_e2e-windows-noop.yml +++ b/.github/workflows/verify_e2e-windows-noop.yml @@ -25,7 +25,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_e2e-windows.yml b/.github/workflows/verify_e2e-windows.yml index c45d40b448..3817af2d8a 100644 --- a/.github/workflows/verify_e2e-windows.yml +++ b/.github/workflows/verify_e2e-windows.yml @@ -11,6 +11,8 @@ on: - 'packages/cli/**' - 'packages/e2e-test/**' - 'packages/create-app/**' + push: + branches: [master] concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -31,7 +33,7 @@ jobs: name: E2E Windows ${{ matrix.node-version }} steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -78,7 +80,7 @@ jobs: uses: browser-actions/setup-chrome@803ef6dfb4fdf22089c9563225d95e4a515820a0 # latest - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} diff --git a/.github/workflows/verify_fossa.yml b/.github/workflows/verify_fossa.yml index e99ad22a9b..126d70b9c8 100644 --- a/.github/workflows/verify_fossa.yml +++ b/.github/workflows/verify_fossa.yml @@ -14,7 +14,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite-noop.yml b/.github/workflows/verify_microsite-noop.yml index f4c5ea4104..85cb1e3fee 100644 --- a/.github/workflows/verify_microsite-noop.yml +++ b/.github/workflows/verify_microsite-noop.yml @@ -21,7 +21,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite.yml b/.github/workflows/verify_microsite.yml index 26c2414589..2507428ec8 100644 --- a/.github/workflows/verify_microsite.yml +++ b/.github/workflows/verify_microsite.yml @@ -24,7 +24,7 @@ jobs: name: Microsite steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite_accessibility-noop.yml b/.github/workflows/verify_microsite_accessibility-noop.yml index 49721e7f51..7d4028e2dd 100644 --- a/.github/workflows/verify_microsite_accessibility-noop.yml +++ b/.github/workflows/verify_microsite_accessibility-noop.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_microsite_accessibility.yml b/.github/workflows/verify_microsite_accessibility.yml index bdf9e56556..e22241b3e3 100644 --- a/.github/workflows/verify_microsite_accessibility.yml +++ b/.github/workflows/verify_microsite_accessibility.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook-noop.yml b/.github/workflows/verify_storybook-noop.yml index 115c79c9c3..5b41d76e4c 100644 --- a/.github/workflows/verify_storybook-noop.yml +++ b/.github/workflows/verify_storybook-noop.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/.github/workflows/verify_storybook.yml b/.github/workflows/verify_storybook.yml index 082142be82..5ddd88b92d 100644 --- a/.github/workflows/verify_storybook.yml +++ b/.github/workflows/verify_storybook.yml @@ -28,7 +28,7 @@ jobs: name: Storybook steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit @@ -42,20 +42,23 @@ jobs: node-version: ${{ matrix.node-version }} registry-url: https://registry.npmjs.org/ # Needed for auth - name: yarn install - uses: backstage/actions/yarn-install@25145dd4117d50e1da9330e9ed2893bc6b75373e # v0.6.15 + uses: backstage/actions/yarn-install@c5c3b91fe86c59a87cf9782de1f89e48e19d4492 # v0.6.16 with: cache-prefix: ${{ runner.os }}-v${{ matrix.node-version }} - name: storybook yarn install run: yarn install --immutable working-directory: storybook + # Only for verification, the canon one is what we upload to Chromatic - run: yarn build-storybook + - run: yarn --cwd packages/canon build-storybook + - uses: chromaui/action@0efa3230f403b7848d5d65c6ce140b617fb68380 # v11 with: token: ${{ secrets.GITHUB_TOKEN }} # projectToken intentionally shared to allow collaborators to run Chromatic on forks # https://www.chromatic.com/docs/custom-ci-provider#run-chromatic-on-external-forks-of-open-source-projects - projectToken: 9tzak77m9nj - workingDir: storybook - storybookBuildDir: dist + projectToken: chpt_dab72dc0f97d55b + workingDir: packages/canon + storybookBuildDir: storybook-static diff --git a/.github/workflows/verify_windows.yml b/.github/workflows/verify_windows.yml index 189bcb09cd..e3f6959929 100644 --- a/.github/workflows/verify_windows.yml +++ b/.github/workflows/verify_windows.yml @@ -29,7 +29,7 @@ jobs: steps: - name: Harden Runner - uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1 + uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2 with: egress-policy: audit diff --git a/ADOPTERS.md b/ADOPTERS.md index c2c2388497..b31e621938 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -276,4 +276,7 @@ _You can do this by using the [Adopter form](https://info.backstage.spotify.com/ | [Cigna](https://www.cigna.com/) / [Evernorth](https://www.evernorth.com/) | [@raphtalia](https://github.com/raphtalia), [Devon Paluso](mailto:Devon.Paluso@evernorth.com), [Bryan Rego](mailto:Bryan.Rego@evernorth.com), [Ian Skillings](mailto:Ian.Skillings@evernorth.com) | Internal developer portal providing TechDocs, software templates, centralized secret management, with information consolidation from ServiceNow, Okta, GitHub, GitLab, and WebEx. | | [Infobip](https://www.infobip.com/) | [Antonio Ereiz](https://github.com/SonilPro) | Visual representation of all our entities registered within an existing internal catalog, along with a UI for editing their manifests. It serves as the go-to place for new internal tools that require a user interface and provides standardization of new components using Software Templates. | [CloudScript](https://www.cloudscript.com.br/) | [Helias Rodrigues](https://github.com/xcloudscript) | We use it to centralize and organize the components of our internal development platform. In addition, it provides an integrated experience for developers by using all the core modules and some plugins. -| [Alauda](https://www.alauda.io/) | [Mario](https://github.com/mario-mui) | We use it to centralize and organize the components of our internal development platform. In addition, it provides environment templates for developers to create development testing or others environments \ No newline at end of file +| [Alauda](https://www.alauda.io/) | [Mario](https://github.com/mario-mui) | We use it to centralize and organize the components of our internal development platform. In addition, it provides environment templates for developers to create development testing or others environments +| [New10](https://www.new10.com/) | [Cleber Gasparoto](https://github.com/chgasparoto) | We use Backstage as our internal developer portal to catalog services across teams, implement custom Tech Insights for ensuring service standards adoption, and centralize API specifications to streamline development processes and cross-team collaboration. +| [Tele2 Kazakhstan](https://tele2.kz/) / [Altel Digital](https://digital.altel.kz/) | [Kuanysh Bekkulov](https://www.linkedin.com/in/kuanysh-bekkulov/), [Alexandr Puzeyev](https://www.linkedin.com/in/alexandr-puzeyev/) | Developer portal: services, components, APIs, and resources; includes documentation (Docs-as-Code), service templates, and plugins for integration with internal systems and tools. +| [Axelerant](https://www.axelerant.com/) | [Zeshan Ziya](https://github.com/zeshanziya) | Developer portal, main gateway to infrastructure, documentation, internal tooling, and service catalog with a focus on project visibility. diff --git a/OWNERS.md b/OWNERS.md index 6f6fea1d67..0932d3386b 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -10,7 +10,6 @@ Team: @backstage/maintainers | Patrik Oldsberg | Spotify | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | | Fredrik Adelöw | Spotify | [freben](https://github.com/freben) | `freben#3926` | | Ben Lambert | Spotify | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | -| Johan Haals | Spotify | [jhaals](https://github.com/jhaals) | `Johan#0679` | ## Project Areas @@ -27,11 +26,21 @@ Scope: The catalog plugin and catalog model | Ben Lambert | Spotify | Cubic Belugas | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | | Camila Loiola | Spotify | Cubic Belugas | [camilaibs](http://github.com/camilaibs) | `camilal#0226` | | Fredrik Adelöw | Spotify | Cubic Belugas | [freben](https://github.com/freben) | `freben#3926` | -| Johan Haals | Spotify | Cubic Belugas | [jhaals](https://github.com/jhaals) | `Johan#0679` | | Mihai Tabara | Spotify | Cubic Belugas | [MihaiTabara](http://github.com/MihaiTabara) | `mihait#3107` | | Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | | Vincenzo Scamporlino | Spotify | Cubic Belugas | [vinzscam](http://github.com/vinzscam) | `vinzscam#6944` | +### Design System + +Team: @backstage/design-system-maintainers + +Scope: The Backstage design system, component library, as well as surrounding tooling such as Storybook. + +| Name | Organization | Team | GitHub | Discord | +| ------------------- | ------------ | ------------- | --------------------------------------------- | ------------- | +| Charles de Dreuille | Spotify | | [cdedreuille](https://github.com/cdedreuille) | `cdedreuille` | +| Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip` | + ### Home Team: @backstage/home-maintainers @@ -91,7 +100,6 @@ Scope: The Permission Framework and plugins integrating with the permission fram | Ben Lambert | Spotify | Cubic Belugas | [benjdlambert](https://github.com/benjdlambert) | `blam#2159` | | Camila Loiola | Spotify | Cubic Belugas | [camilaibs](http://github.com/camilaibs) | `camilal#0226` | | Fredrik Adelöw | Spotify | Cubic Belugas | [freben](https://github.com/freben) | `freben#3926` | -| Johan Haals | Spotify | Cubic Belugas | [jhaals](https://github.com/jhaals) | `Johan#0679` | | Mihai Tabara | Spotify | Cubic Belugas | [MihaiTabara](http://github.com/MihaiTabara) | `mihait#3107` | | Patrik Oldsberg | Spotify | Cubic Belugas | [Rugvip](https://github.com/Rugvip) | `Rugvip#0019` | | Vincenzo Scamporlino | Spotify | Cubic Belugas | [vinzscam](http://github.com/vinzscam) | `vinzscam#6944` | @@ -218,6 +226,7 @@ Scope: The Backstage Documentation | Maintainer | Organization | GitHub | Discord | | ------------ | ------------ | --------------------------------------------- | -------------- | | Stefan Ålund | Spotify | [stefanalund](https://github.com/stefanalund) | `stalund#9602` | +| Johan Haals | Spotify | [jhaals](https://github.com/jhaals) | `Johan#0679` | ## Emeritus End User Sponsors diff --git a/app-config.yaml b/app-config.yaml index cb70170541..64c2fa5c4c 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -221,6 +221,17 @@ integrations: # apiBaseUrl: server.bitbucket.com # username: ${BITBUCKET_SERVER_USERNAME} # appPassword: ${BITBUCKET_SERVER_APP_PASSWORD} + + # azureBlobStorage: + # - accountName: ${ACCOUNT_NAME} # required + # endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken + # sasToken: ${SAS_TOKEN} + # aadCredential: + # clientId: ${CLIENT_ID} + # tenantId: ${TENANT_ID} + # clientSecret: ${CLIENT_SECRET} + # accountKey: ${ACCOUNT_KEY} + azure: - host: dev.azure.com token: ${AZURE_TOKEN} @@ -245,6 +256,14 @@ catalog: - Domain - Location providers: + azureBlob: + accountName: ${ACCOUNT_NAME} + containerName: ${CONTAINER_NAME} + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } backstageOpenapi: plugins: - catalog diff --git a/beps/NNNN-template/README.md b/beps/NNNN-template/README.md index 3ecb1ffb4e..2fce6ecd95 100644 --- a/beps/NNNN-template/README.md +++ b/beps/NNNN-template/README.md @@ -1,6 +1,6 @@ --- title: BEP Title -status: provisional +status: implementable authors: - '@ghost' owners: @@ -13,16 +13,10 @@ creation-date: yyyy-mm-dd # BEP: - - -[**Discussion Issue**](https://github.com/backstage/backstage/issues/NNNNN) - - [Summary](#summary) - [Motivation](#motivation) - [Goals](#goals) diff --git a/beps/README.md b/beps/README.md index 531bd15f50..84bf967b5c 100644 --- a/beps/README.md +++ b/beps/README.md @@ -4,19 +4,18 @@ A Backstage Enhancement Proposal (BEP) is a way to propose, communicate and coor ## Quick start for the BEP process -1. Discuss the idea with the community and maintainers. Either here on GitHub, Discord, or during community sessions or SIG meetings. - Make sure that others think the work is worth taking up and will help review the BEP and any code changes required. +1. Discuss the idea with the community and maintainers. Either here on GitHub, Discord, or during community sessions or SIG meetings. Make sure that others think the work is worth taking up and will help review the BEP and any code changes required. 1. Make a copy of the [BEP template](./NNNN-template/) directory as `beps/NNNN-short-descriptive-title`, where `NNNN` is the next available number padded with leading zeroes. 1. Fill out as much of the YAML metadata as you can. 1. Fill out the template as best you can. 1. If you want the BEP to be owned by a particular project area, add an entry for the BEP folder to [CODEOWNERS](../.github/CODEOWNERS). -1. Create a PR for the BEP. Title it "BEP: <title>". Aim to get the high level goals clarified and avoid getting hung up on specific details. The PR can be merged early and iterated on. -1. Once the BEP is ready to be merged, create a [feature issue](https://github.com/backstage/backstage/issues/new?template=feature.yaml) titled "BEP: <title>". Use the summary of the BEP as description and link to the BEP PR in the context section. Once the PR is merged, the issue should be updated to link to the BEP folder instead. This issue will serve as a general discussion issue for the BEP. -1. Once the initial BEP is merged you should keep iterating on it until it is ready to leave that `provisional` state. Leaving the `provisional` state is a decision made by the project area maintainers. +1. Create a PR for the BEP. Title it "BEP: <title>". Aim to get the high level goals clarified and avoid getting hung up on specific details. The PR can be iterated on until the BEP is ready to be merged. +1. The relevant maintainers will review the BEP and provide feedback. It can also be useful to join relevant SIG meetings to discuss the BEP, to help drive it forward faster. +1. Let the maintainers know when you think the BEP is ready to be merged. At this point the BEP should be fully filled out and ready for implementation, along with a clear owner for the work. -Just because a BEP is merged does not mean it is complete or approved for implementation. Any BEP marked as `provisional` is a working document and subject to change. +The merging of a BEP means that it is approved for implementation and has an owner that is responsible for said implementation. Up until that point, the author(s) of the BEP are responsible for driving the BEP forward. -The authors of the BEP are also responsible for driving the BEP forward all the way to implementation. The approval of a BEP is not a commitment to implement it. +While the BEP PR is open the owner can open separate PRs to ship experimental features in support of the BEP to help drive the design forward, and these may be merged pending usual PR review. If the BEP is withdrawn or rejected these features should generally be removed. ## FAQs @@ -38,7 +37,7 @@ No, except for plugins that implement core features of Backstage. The BEP proces ### Can I update an existing BEP? -Yes! As long as the BEP is still in the `provisional` state you should keep iterating on it. Please keep each PR focused on a single topic and avoid long-running and overly broad PRs. +Yes! As long as the BEP is in the `implementable` state. Updates should however only be done based on new discoveries during the implementation phase. If you want to make a significant change to a BEP that has already been approved, you should open a new BEP to replace the old one. ### Can I update a BEP that was submitted by someone else? @@ -48,6 +47,10 @@ Yes! BEPs are living documents and anyone can suggest changes to them. We encour Architecture Decision Records (ADRs) are used to document decisions made for development within the Backstage project. They are not intended to be used for proposing new features or changes to Backstage. +### What's does it mean for a BEP to be in "provisional" state? + +This is a state from an older version of the BEP process, and means that it has been approved as work to be done but the exact design is not yet agreed upon. BEPs in this state need to be moved to the `implementable` state before they can be implemented. + ### My FAQ isn't answered here! The BEP process is still evolving! @@ -72,13 +75,10 @@ At the start of each BEP is a YAML document that contains metadata about the BEP The BEP Status is critical to clearly communicate the status of each BEP. Each BEP must have its status field set to one of the following values: -- `provisional`: The BEP has been proposed and is actively being defined. The BEP as been approved by the owning project area maintainers as work to be done. -- `implementable`: The approvers have approved this BEP for implementation. -- `implemented`: The BEP has been implemented and is no longer actively changed. -- `deferred`: The BEP is proposed but not actively being worked on. -- `rejected`: The approvers and authors have decided that this BEP is not moving forward. - The BEP is kept around as a historical document. -- `withdrawn`: The authors have withdrawn the BEP. +- `implementable`: The BEP has been approved for implementation by the owning project area maintainers. +- `implemented`: The BEP has been implemented. +- `deferred`: The BEP was approved but is no longer being actively worked on. If anyone wishes to pick up the work they can move it back to the `implementable` state. +- `rejected`: The approvers and authors have decided that this BEP is not moving forward. The BEP is kept around as a historical document. - `replaced`: The BEP has been replaced by a new BEP. ### Prior Art diff --git a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild index fa8e42482b..47fd506a34 100644 --- a/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild +++ b/contrib/docker/frontend-with-nginx/Dockerfile.dockerbuild @@ -35,7 +35,7 @@ -FROM node:16-buster AS build +FROM node:20-buster AS build RUN mkdir /app COPY . /app diff --git a/docs/deployment/flightcontrol.md b/contrib/docs/tutorials/flightcontrol-deployment.md similarity index 98% rename from docs/deployment/flightcontrol.md rename to contrib/docs/tutorials/flightcontrol-deployment.md index df0c9284fb..aee915ba2f 100644 --- a/docs/deployment/flightcontrol.md +++ b/contrib/docs/tutorials/flightcontrol-deployment.md @@ -1,9 +1,4 @@ ---- -id: flightcontrol -title: Deploying with Flightcontrol -sidebar_label: AWS Fargate via Flightcontrol -description: Deploying Backstage to AWS Fargate via Flightcontrol ---- +# Deploying Backstage to AWS with Flightcontrol This guide explains how to deploy Backstage to [Flightcontrol](https://www.flightcontrol.dev?ref=backstage), a platform that fully automates deployments to Amazon Web Services (AWS). Flightcontrol supports git-driven and image registry deployments. diff --git a/docs/deployment/heroku.md b/contrib/docs/tutorials/heroku-deployment.md similarity index 96% rename from docs/deployment/heroku.md rename to contrib/docs/tutorials/heroku-deployment.md index 8961848894..2dea1f021c 100644 --- a/docs/deployment/heroku.md +++ b/contrib/docs/tutorials/heroku-deployment.md @@ -1,9 +1,4 @@ ---- -id: heroku -title: Deploying with Heroku -sidebar_label: Heroku -description: How to deploy Backstage to Heroku ---- +# Deploying Backstage to Heroku Heroku is a Platform as a Service (PaaS) designed to simplify application deployment. diff --git a/docs/deployment/koyeb.md b/contrib/docs/tutorials/koyeb-deployment.md similarity index 86% rename from docs/deployment/koyeb.md rename to contrib/docs/tutorials/koyeb-deployment.md index 3e30881752..75d42d8814 100644 --- a/docs/deployment/koyeb.md +++ b/contrib/docs/tutorials/koyeb-deployment.md @@ -1,9 +1,4 @@ ---- -id: koyeb -title: Deploying with Koyeb -sidebar_label: Koyeb -description: How to deploy Backstage to Koyeb ---- +# Deploying Backstage to Koyeb This guide explains how to deploy Backstage to [Koyeb](https://www.koyeb.com/), a serverless platform that provides the fastest way to deploy applications globally. Koyeb supports git-driven and container-based deployments. @@ -31,7 +26,7 @@ backend: ## Push and deploy Backstage to Koyeb -Push your Backstage application with its [Dockerfile](docker.md) to Koyeb using the following command: +Push your Backstage application with its [Dockerfile](https://backstage.io/docs/deployment/docker) to Koyeb using the following command: ```bash koyeb app init example-backstage \ diff --git a/contrib/scaffolder/template-testing-dry-run.md b/contrib/scaffolder/template-testing-dry-run.md index 70e0c572ab..12c4210ed6 100644 --- a/contrib/scaffolder/template-testing-dry-run.md +++ b/contrib/scaffolder/template-testing-dry-run.md @@ -26,7 +26,6 @@ import { readFile, writeFile } from 'node:fs/promises'; import { gzipSync } from 'node:zlib'; import { ensureDir } from 'fs-extra'; import { program } from 'commander'; -import fetch from 'node-fetch'; import ora from 'ora'; import readdir from 'recursive-readdir'; import { parse } from 'yaml'; diff --git a/docs/architecture-decisions/adr013-use-node-fetch.md b/docs/architecture-decisions/adr013-use-node-fetch.md index f6f022ed29..e65cf0a97b 100644 --- a/docs/architecture-decisions/adr013-use-node-fetch.md +++ b/docs/architecture-decisions/adr013-use-node-fetch.md @@ -1,10 +1,16 @@ --- id: adrs-adr013 -title: 'ADR013: Proper use of HTTP fetching libraries' +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. --- +:::note Superseded + +This ADR has been superseded by [ADR014](./adr014-use-fetch.md) and no longer applies. + +::: + ## Context Using multiple HTTP packages for data fetching increases the complexity and the diff --git a/docs/architecture-decisions/adr014-use-fetch.md b/docs/architecture-decisions/adr014-use-fetch.md new file mode 100644 index 0000000000..8454e69e7c --- /dev/null +++ b/docs/architecture-decisions/adr014-use-fetch.md @@ -0,0 +1,80 @@ +--- +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. +--- + +## Context + +Until now we have been recommending the use of `node-fetch` in Node.js contexts +through [ADR013](./adr013-use-node-fetch.md). Since then, Backstage has had its +minimum requirements upgraded to Node.js 20 or newer. The Node.js platform has +established a stable, reliable `undici` based native `fetch` in these versions. +Additionally, there are [some issues](https://github.com/backstage/backstage/issues/24590) +with using third party libraries that only appeared in newer versions of +Node.js. + +## Decision + +All code that is executed in Node.js (including backend and CLIs) should use the +native `fetch` for HTTP data fetching, and `typeof fetch` as the TypeScript type +in code where a `fetch` implementation can be injected or is referred to. +Example: + +```ts +import { ResponseError } from '@backstage/errors'; + +// this is implicitly global.fetch +const response = await fetch('https://example.com/api/v1/users.json'); +if (!response.ok) { + throw await ResponseError.fromResponse(response); +} +const users = await response.json(); +``` + +Frontend plugins and packages should prefer to use the +[`fetchApiRef`](https://backstage.io/docs/reference/core-plugin-api.fetchapiref). + +```ts +import { useApi } from '@backstage/core-plugin-api'; + +// Inside some React component... +const { fetch } = useApi(fetchApiRef); + +const response = await fetch('https://example.com/api/v1/users.json'); +if (!response.ok) { + throw await ResponseError.fromResponse(response); +} +const users = await response.json(); +``` + +Isomorphic packages should have a dependency on the `cross-fetch` package for +mocking and type definitions. Preferably, classes and functions in isomorphic +packages should accept an argument of type `typeof fetch` to let callers supply +their preferred implementation of `fetch`. This lets them adorn the calls with +auth or other information, and track metrics etc, in a cross-platform way. +Example: + +```ts +import crossFetch from 'cross-fetch'; + +export class MyClient { + private readonly fetch: typeof crossFetch; + + constructor(options: { fetch?: typeof crossFetch }) { + this.fetch = options.fetch || crossFetch; + } + + async users() { + return await this.fetch('https://example.com/api/v1/users.json'); + } +} +``` + +## Consequences + +We will gradually transition away from third party `fetch` replacement packages +such as `node-fetch` and others on the Node.js platform. + +The `@mswjs/interceptors` library as used by `msw` version 1.x [does not support native fetch properly](https://github.com/mswjs/msw/issues/1563#issuecomment-1694249010) and likely never will. When you switch to using native fetch, you may see `msw` based tests start to fail to both capture and block traffic. Certain tests may need to be rewritten to use `msw` 2.x or newer instead, which uses a newer version of the interceptors. diff --git a/docs/auth/google/provider.md b/docs/auth/google/provider.md index 109c2ddd9f..e03985d432 100644 --- a/docs/auth/google/provider.md +++ b/docs/auth/google/provider.md @@ -89,6 +89,6 @@ backend.add(import('@backstage/plugin-auth-backend-module-google-provider')); ## Adding the provider to the Backstage frontend -To add the provider to the frontend, add the `googleAuthApi` reference and +To add the provider to the frontend, add the `googleAuthApiRef` reference and `SignInPage` component as shown in [Adding the provider to the sign-in page](../index.md#sign-in-configuration). diff --git a/docs/auth/service-to-service-auth.md b/docs/auth/service-to-service-auth.md index 13516a1117..126b136d0b 100644 --- a/docs/auth/service-to-service-auth.md +++ b/docs/auth/service-to-service-auth.md @@ -412,3 +412,31 @@ Each entry has one or more of the following fields: # Also supports the shorthand form: # action: create, read ``` + +## Adding custom or logic for validation and issuing of tokens + +The `pluginTokenHandlerDecoratorServiceRef` can be used to decorate the existing token handler without having to re-implement the entire `AuthService` implementation. +This is particularly useful when you want to add additional logic to the handler, such as logging or metrics or custom token validation. + +The `PluginTokenHandler` interface has two methods: + +- `issueToken`: This method is used to issue a token for a plugin. It takes in the `pluginId` and `targetPluginId` as arguments, and an optional `limitedUserToken` object which can be used to issue a token on behalf of another user. The method returns a promise that resolves to an object containing the issued token. + +- `verifyToken`: This method is used to verify a token. It takes in the token as an argument and returns a promise that resolves to an object containing the subject of the token and an optional limited user token. + +```ts +import { + PluginTokenHandler, + pluginTokenHandlerDecoratorServiceRef, +} from '@backstage/backend-defaults/auth'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; + +const decoratedPluginTokenHandler = createServiceFactory({ + service: pluginTokenHandlerDecoratorServiceRef, + deps: {}, + async factory() { + return (defaultImplementation: PluginTokenHandler) => + new CustomTokenHandler(defaultImplementation); + }, +}); +``` diff --git a/docs/backend-system/architecture/07-feature-loaders.md b/docs/backend-system/architecture/07-feature-loaders.md index 43954ec443..b2cc574bf9 100644 --- a/docs/backend-system/architecture/07-feature-loaders.md +++ b/docs/backend-system/architecture/07-feature-loaders.md @@ -73,6 +73,29 @@ export default createBackendFeatureLoader({ }); ``` +### Overriding service factories + +Service factories registered by feature loaders have lower priority than ones added directly via `backend.add`. This allows you to use a feature loader for a larger number of service implementations, but still override individual services. + +The ordering in which different feature loaders or service factories are added does not matter. There is also no priority between feature loaders, if two different feature loaders add a factory for the same service, the backend will fail to start. + +```ts +const backend = createBackend(); + +backend.add( + createBackendFeatureLoader({ + async *loader() { + yield import('./commonDiscoveryService'); // discovery service + yield import('./commonRootLoggerService'); // root logger service + }, + }), +); + +backend.add(import('./myDiscoveryService')); // discovery service +``` + +The result of the above example is that the backend starts up with `./myDiscoveryService` as the discovery service implementation, while `./commonDiscoveryService` is ignored. The `./commonRootLoggerService` will still be used. + ### Dynamic logic A feature loader can also be asynchronous, and for example fetch data from an external source to determine which features to load: diff --git a/docs/backend-system/core-services/discovery.md b/docs/backend-system/core-services/discovery.md index 455e398d8b..4324edbbf9 100644 --- a/docs/backend-system/core-services/discovery.md +++ b/docs/backend-system/core-services/discovery.md @@ -16,7 +16,6 @@ import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; -import { fetch } from 'node-fetch'; createBackendPlugin({ pluginId: 'example', diff --git a/docs/backend-system/core-services/http-auth.md b/docs/backend-system/core-services/http-auth.md index 13938c921d..f3ce96fb25 100644 --- a/docs/backend-system/core-services/http-auth.md +++ b/docs/backend-system/core-services/http-auth.md @@ -102,6 +102,45 @@ or [contribute](https://github.com/backstage/backstage/blob/master/CONTRIBUTING. ::: +### Custom token extraction logic + +In some cases, you might want to customize how tokens are extracted from incoming requests. It might be that you want to extract tokens from a different location in the request. To support this you can supply your own slightly modified httpAuth service. The `DefaultHttpAuthService` class is exported from `@backstage/backend-defaults/httpAuth` and it's static `create` method can be used to pass in a custom `getTokenFromRequest` extraction function. + +```ts +import { DefaultHttpAuthService } from '@backstage/backend-defaults/httpAuth'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; + +export const customizedAuthServiceFactory = createServiceFactory({ + service: coreServices.httpAuth, + deps: { + auth: coreServices.auth, + discovery: coreServices.discovery, + plugin: coreServices.pluginMetadata, + }, + async factory({ auth, discovery, plugin }) { + return DefaultHttpAuthService.create({ + auth, + discovery, + pluginId: plugin.getId(), + getTokenFromRequest: req => { + let token: string | undefined; + const header = req.headers.some_random_header; + if (typeof header === 'string') { + const parts = header.split(' '); + if (parts.length === 2 && parts[0] === 'Bearer') { + token = parts[1]; + } + } + return { token }; + }, + }); + }, +}); +``` + This service has no configuration options, but it abides by the policies you have set up using [the `httpRouter` service](./http-router.md) for your routes, if any. diff --git a/docs/backend-system/core-services/http-router.md b/docs/backend-system/core-services/http-router.md index 6ab8218c83..c354f4fceb 100644 --- a/docs/backend-system/core-services/http-router.md +++ b/docs/backend-system/core-services/http-router.md @@ -70,4 +70,67 @@ access the incoming credentials. ## Configuring the service -This service does not have any configuration options. +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: + +```ts +import { + createLifecycleMiddleware, + createCookieAuthRefreshMiddleware, + createCredentialsBarrier, + createAuthIntegrationRouter, +} from '@backstage/backend-defaults/httpRouter'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; + +const backend = createBackend(); + +backend.add( + createServiceFactory({ + service: coreServices.httpRouter, + initialization: 'always', + deps: { + plugin: coreServices.pluginMetadata, + config: coreServices.rootConfig, + lifecycle: coreServices.lifecycle, + rootHttpRouter: coreServices.rootHttpRouter, + auth: coreServices.auth, + httpAuth: coreServices.httpAuth, + }, + async factory({ + auth, + httpAuth, + config, + plugin, + rootHttpRouter, + lifecycle, + }) { + const router = PromiseRouter(); + + rootHttpRouter.use(`/api/${plugin.getId()}`, router); + + const credentialsBarrier = createCredentialsBarrier({ + httpAuth, + config, + }); + + router.use(createAuthIntegrationRouter({ auth })); + router.use(createLifecycleMiddleware({ lifecycle })); + router.use(credentialsBarrier.middleware); + router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth })); + + // Add a custom healthcheck endpoint for all plugins. + router.use('/health', (_, res) => { + res.status(200); + }); + + return { + use(handler: Handler): void { + router.use(handler); + }, + addAuthPolicy(policy: HttpRouterServiceAuthPolicy): void { + credentialsBarrier.addAuthPolicy(policy); + }, + }; + }, + }), +); +``` diff --git a/docs/backend-system/core-services/root-health.md b/docs/backend-system/core-services/root-health.md index 663dd699ae..fa147499a6 100644 --- a/docs/backend-system/core-services/root-health.md +++ b/docs/backend-system/core-services/root-health.md @@ -38,3 +38,29 @@ backend.add( }), ); ``` + +### Custom headers in health check responses + +While not implemented directly in the root health service, the default implementation of the [RootHttpRouter](./root-http-router.md) service includes a configuration option to set additional headers to include in health check responses. For example, you can add a `service-name` header using the following configuration: + +```yaml +backend: + health: + headers: + service-name: my-service +``` + +It can be a good idea to set a header for your health check responses that +uniquely identifies your service in a multi-service environment. This ensures +that the health check that is configured for your service is actually hitting +your service and not another. + +For example, if using Envoy you can use the [`service_name_matcher`](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/health_checking#health-check-identity) configuration and +set the `x-envoy-upstream-healthchecked-cluster` header to a matching value. For example: + +```yaml +backend: + health: + headers: + x-envoy-upstream-healthchecked-cluster: my-service +``` diff --git a/docs/backend-system/core-services/root-http-router.md b/docs/backend-system/core-services/root-http-router.md index a2316b957b..9ee8599eb5 100644 --- a/docs/backend-system/core-services/root-http-router.md +++ b/docs/backend-system/core-services/root-http-router.md @@ -42,6 +42,29 @@ createBackendPlugin({ ## Configuring the service +### Via `app-config.yaml` + +The `app-config.yaml` file provides configurable options that can be adjusted to meet your `RootHttpRouterService` specific requirements: + +```yaml +backend: + lifecycle: + # (Optional) The maximum time that paused requests will wait for the service to start, before returning an error (defaults to 5 seconds). + # Supported formats: + # - 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 }`. + startupRequestPauseTimeout: { seconds: 10 } + # (Optional) The minimum time that the HTTP server will delay the shutdown of the backend. During this delay health checks will be set to failing, allowing traffic to drain (defaults to 0 seconds). + # Supported formats: + # - 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 } +``` + +### Via Code + There's additional options that you can pass to configure the root HTTP Router service. These options are passed when you call `createBackend`. - `indexPath` - optional path to forward all unmatched requests to. Defaults to `/api/app` which is the `app-backend` plugin responsible for serving the frontend application through the backend. diff --git a/docs/backend-system/core-services/scheduler.md b/docs/backend-system/core-services/scheduler.md index e4c67a1199..154878ddfc 100644 --- a/docs/backend-system/core-services/scheduler.md +++ b/docs/backend-system/core-services/scheduler.md @@ -16,7 +16,6 @@ import { coreServices, createBackendPlugin, } from '@backstage/backend-plugin-api'; -import { fetch } from 'node-fetch'; createBackendPlugin({ pluginId: 'example', diff --git a/docs/deployment/backstage-deploy/aws.md b/docs/deployment/backstage-deploy/aws.md deleted file mode 100644 index 818850a6f5..0000000000 --- a/docs/deployment/backstage-deploy/aws.md +++ /dev/null @@ -1,182 +0,0 @@ ---- -id: aws-lightsail -title: Deploying Backstage on AWS Lightsail -sidebar_label: AWS Lightsail -description: How to deploy Backstage on AWS Lightsail ---- - -> **DISCLAIMER: The `deploy` command is in alpha and still experimental. Do not use the `deploy` command for production deployments.** - -Getting started with Backstage often involves setting up an instance on a cloud provider and sharing it with your team so they can experiment. To make this cloud deployment easier, we've built a `deploy` command to stand up a proof-of-concept instance on AWS (using Lightsail). - -## What is AWS Lightsail - -:::tip - -AWS offers a free tier for up to three months on $10 USD/month Container service (Micro -1 node). By default we use the `nano` node, so if you are a new user this approach shouldn't cost you anything. For more information, refer to the [pricing](https://aws.amazon.com/lightsail/pricing/) documentation. - -::: - -AWS Lightsail offers a simple way to run containers in the cloud. To learn more about AWS Lightsail, please refer to the [official documentation](https://lightsail.aws.amazon.com/ls/docs/en_us/articles/amazon-lightsail-container-services-deployments). - -## Creating user in AWS - -- Open the AWS console and navigate to the IAM section -- In the left side menu click on `Users` and then click on `Add users` -- Specify a username and then click on `Next` -- Afterwards you can assign permissions, select `Attach policies directly` and then click on `Create policy`. - This should take you to a new window in which you can create a new policy based on `JSON`. - Copy over the following: - -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "VisualEditor0", - "Effect": "Allow", - "Action": [ - "ecr:DescribeImageReplicationStatus", - "ecr:ListTagsForResource", - "ecr:UploadLayerPart", - "ecr:BatchGetRepositoryScanningConfiguration", - "ecr:DeleteRepository", - "ecr:GetRegistryScanningConfiguration", - "ecr:CompleteLayerUpload", - "ecr:TagResource", - "ecr:DescribeRepositories", - "ecr:DeleteRepositoryPolicy", - "ecr:BatchCheckLayerAvailability", - "ecr:GetLifecyclePolicy", - "ecr:GetRegistryPolicy", - "ecr:PutLifecyclePolicy", - "ecr:DescribeImageScanFindings", - "ecr:GetLifecyclePolicyPreview", - "ecr:CreateRepository", - "ecr:DescribeRegistry", - "ecr:GetDownloadUrlForLayer", - "ecr:GetAuthorizationToken", - "ecr:DeleteLifecyclePolicy", - "ecr:PutImage", - "ecr:UntagResource", - "ecr:SetRepositoryPolicy", - "ecr:BatchGetImage", - "ecr:InitiateLayerUpload", - "ecr:GetRepositoryPolicy", - "lightsail:CreateContainerService", - "lightsail:GetKeyPair", - "lightsail:GetContainerServiceDeployments", - "lightsail:CreateContainerServiceRegistryLogin", - "lightsail:GetContainerImages", - "lightsail:UntagResource", - "lightsail:RegisterContainerImage", - "lightsail:GetContainerServices", - "lightsail:GetContainerServicePowers", - "lightsail:GetKeyPairs", - "lightsail:CreateContainerServiceDeployment", - "lightsail:GetContainerServiceMetricData", - "lightsail:GetContainerAPIMetadata", - "lightsail:DeleteContainerService", - "lightsail:GetContainerLog", - "lightsail:TagResource" - ], - "Resource": "*" - }, - { - "Sid": "Statement1", - "Effect": "Allow", - "Action": [], - "Resource": [] - } - ] -} -``` - -Then click on `Next` and give the policy a name and a description of your liking. Afterwards, click on `Create policy`. - -- Navigate back to the user creation window and press on the refresh button and search for the policy you just created. Now, create the user. -- Now you will be redirected to all users, click on the user you just created and click on `Security credentials` -- Scroll below and click on `Create access key` -- Choose `Command Line Interface (CLI)` -- Now export the following values - -```bash -$ export AWS_ACCESS_KEY_ID=... (first value) -$ export AWS_SECRET_ACCESS_KEY=.... (second secret value) -``` - -## Configuring the Pulumi CLI - -Second, install the [Pulumi CLI](https://www.pulumi.com/docs/get-started/install/) - `backstage-deploy` uses it to -simplify the management of cloud resources (Pulumi allows us to simply specify the desired "target cloud state", and -Pulumi will intelligently create/modify/delete resources to reach that state. Nice!). - -Then we need to execute the following commands, to set Pulumi up: - -:::tip - -Make sure to store your passphrase somewhere safe as it is used to encrypt/decrypt your Pulumi config. - -::: - -```bash -$ pulumi login --local -$ export PULUMI_CONFIG_PASSPHRASE="" -``` - -By using `pulumi login --local` we are making sure that Pulumi stores our state on the local file disk. The environment variable `PULUMI_CONFIG_PASSPHRASE` is used by Pulumi to generate a unique key for your stack - -## Deploying your instance on Lightsail - -:::tip - -Make sure that [Docker](https://docs.docker.com/) is running on your machine before you start this section. - -::: - -After you have made your changes to your local instance, it's time to deploy it on Lightsail. - -First, we need to configure a new `app-config` file and update the `baseUrl`. - -```bash -$ touch app-config.deployment.yaml -``` - -And then update the file with the following yaml: - -```yaml -app: - baseUrl: ${BACKSTAGE_HOST} - -backend: - baseUrl: ${BACKSTAGE_HOST} -``` - -The environment variable `BACKSTAGE_HOST` will be set to the endpoint that AWS Lightsail creates. - -Now we can deploy our instance! - -```bash -$ npx backstage-deploy aws --stack backstage-poc --create-dockerfile -``` - -In the first part of the command, we are specifying that we want to deploy our instance on AWS. With the [`--stack`](https://www.pulumi.com/docs/reference/cli/pulumi_stack/) option, we are providing Pulumi a reference to our container deployment. Furthermore, with the `--create-dockerfile` option, there will be a `Dockerfile` and `.dockerignore` created in the root of the project. - -After running the command, Pulumi will start creating the following resources for you in AWS: - -- ECR Repository -- Lightsail Container Service -- Lightsail Container Service Deployment -- Policy that allows Lightsail to pull from ECR - -If it's the first time building the Docker image, it might take a while for everything to be fully provisioned. After the command is finished running, your Backstage instance should be up and running on AWS Lightsail! 🎉 - -### Cleaning up resources - -Cleaning up the resources is also done with the deploy command. - -```bash -$ npx backstage-deploy aws --stack backstage-poc --destroy -``` - -This will delete everything that was originally created by the `deploy` command. diff --git a/docs/deployment/docker.md b/docs/deployment/docker.md index afab8ef54d..546d027b86 100644 --- a/docs/deployment/docker.md +++ b/docs/deployment/docker.md @@ -5,6 +5,10 @@ sidebar_label: Docker description: How to build a Backstage Docker image for deployment --- +:::note Note +Before you start this section, it would be good to have a basic understanding of Docker and how it works. If you are new to Docker, you can start with the [Docker overview](https://docs.docker.com/get-started/overview/) guide. +::: + This section describes how to build a Backstage App into a deployable Docker image. It is split into three sections, first covering the host build approach, which is recommended due to its speed and more efficient and often simpler @@ -46,8 +50,7 @@ yarn install --immutable yarn tsc # Build the backend, which bundles it all up into the packages/backend/dist folder. -# The configuration files here should match the one you use inside the Dockerfile below. -yarn build:backend --config ../../app-config.yaml --config ../../app-config.production.yaml +yarn build:backend ``` Once the host build is complete, we are ready to build our image. The following @@ -85,6 +88,7 @@ WORKDIR /app # Copy files needed by Yarn COPY --chown=node:node .yarn ./.yarn COPY --chown=node:node .yarnrc.yml ./ +COPY --chown=node:node backstage.json ./ # This switches many Node.js dependencies to production mode. ENV NODE_ENV=production @@ -181,7 +185,7 @@ the repo root: FROM node:20-bookworm-slim AS packages WORKDIR /app -COPY package.json yarn.lock ./ +COPY backstage.json package.json yarn.lock ./ COPY .yarn ./.yarn COPY .yarnrc.yml ./ @@ -219,6 +223,7 @@ WORKDIR /app COPY --from=packages --chown=node:node /app . COPY --from=packages --chown=node:node /app/.yarn ./.yarn COPY --from=packages --chown=node:node /app/.yarnrc.yml ./ +COPY --from=packages --chown=node:node /app/backstage.json ./ RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \ yarn install --immutable @@ -266,7 +271,9 @@ WORKDIR /app # Copy the install dependencies from the build stage and context COPY --from=build --chown=node:node /app/.yarn ./.yarn COPY --from=build --chown=node:node /app/.yarnrc.yml ./ +COPY --from=build --chown=node:node /app/backstage.json ./ COPY --from=build --chown=node:node /app/yarn.lock /app/package.json /app/packages/backend/dist/skeleton/ ./ + # Note: The skeleton bundle only includes package.json files -- if your app has # plugins that define a `bin` export, the bin files need to be copied as well to # be linked in node_modules/.bin during yarn install. diff --git a/docs/deployment/index.md b/docs/deployment/index.md index 0524e71db8..76c8c12932 100644 --- a/docs/deployment/index.md +++ b/docs/deployment/index.md @@ -30,14 +30,7 @@ At Spotify, we deploy software generally by: This method is covered in [Building a Docker image](docker.md) and [Deploying with Kubernetes](k8s.md). -There is also an example of deploying on [Heroku](heroku.md), which only -requires the first two steps. - -There is also a contrib guide to deploying Backstage with -[AWS Fargate and Aurora PostgreSQL](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/aws-fargate-deployment.md). - -Please consider contributing other deployment guides if you get Backstage set up -on common infrastructure, it would be a great benefit to the community. +There are many ways to deploy Backstage! You can find more examples in the community contributed guides found [here](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/). If you need to run Backstage behind a corporate proxy, this [contributed guide](https://github.com/backstage/backstage/blob/master/contrib/docs/tutorials/help-im-behind-a-corporate-proxy.md) diff --git a/docs/features/software-templates/experimental.md b/docs/features/software-templates/experimental.md new file mode 100644 index 0000000000..e37971ad82 --- /dev/null +++ b/docs/features/software-templates/experimental.md @@ -0,0 +1,87 @@ +--- +id: experimental +title: Experimental Features +# prettier-ignore +description: Information on Experimental Features that are currently available in the Scaffolder +--- + +## Introduction + +This section contains information and guides on the experimental features that are currently available in the Scaffolder. Be advised that these features are still in development and may not be fully stable or complete, and are subject to change at any time. + +Please leave feedback on these features in the [Backstage Discord](https://discord.com/invite/MUpMjP2) or by [creating an issue](https://github.com/backstage/backstage/issues/new/choose) on the Backstage GitHub repository. + +## Retries and Recovery + +### TODO + +## Form Decorators + +Form decorators provide the ability to run arbitrary code before the form is submitted along with secrets to the `scaffolder-backend` plugin. They are provided to the `app` using a Utility API. + +#### Installation + +To install the Form Decorators, add the following to your `packages/app/src/apis.ts`: + +```ts + createApiFactory({ + api: formDecoratorsApiRef, + deps: {}, + factory: () => + DefaultScaffolderFormDecoratorsApi.create({ + decorators: [ + // add decorators here + ], + }), + }), +``` + +And then you'll also need to define which decorators run in each template using the `EXPERIMENTAL_formDecorators` key in the template's `spec`: + +```yaml +kind: Template +metadata: + name: my-template +spec: + EXPERIMENTAL_formDecorators: + - id: my-decorator + input: + test: something funky + + parameters: ... + steps: ... +``` + +#### Creating a Decorator + +You can create a decorator using the simple helper method `createScaffolderFormDecorator`: + +```ts +export const mockDecorator = createScaffolderFormDecorator({ + // give the decorator a name + id: 'mock-decorator', + + // define the schema for the input that can be proided in `template.yaml` + schema: { + input: { + test: z => z.string(), + }, + }, + deps: { + // define dependencies here + githubApi: githubAuthApiRef, + }, + decorator: async ( + // Context has all the things needed to write simple decorators + { setSecrets, setFormState, input: { test } }, + // Depepdencies injected here + { githubApi }, + ) => { + // mutate the form state + setFormState(state => ({ ...state, test, mock: 'MOCK' })); + + // mutate the form secrets + setSecrets(state => ({ ...state, GITHUB_TOKEN: 'MOCK_TOKEN' })); + }, +}); +``` diff --git a/docs/features/software-templates/input-examples.md b/docs/features/software-templates/input-examples.md index ef90013e49..0162ffb8f3 100644 --- a/docs/features/software-templates/input-examples.md +++ b/docs/features/software-templates/input-examples.md @@ -198,6 +198,23 @@ parameters: ui:widget: checkboxes ``` +## Markdown text blocks + +```yaml +parameters: + - title: Fill in some steps + properties: + markdown: + type: 'null' # Needs to be quoted + description: | + ## Markdown Text Block + + Standard markdown formatting is supported including *italics*, **bold** and [links](https://example.com) + + * bullet 1 + * bullet 2 +``` + ## Use parameters as condition in steps Conditions use Javascript equality operators. @@ -250,6 +267,54 @@ parameters: - lastName ``` +### Multiple conditional fields with custom ordering + +```yaml +parameters: + - title: Fill in some steps + ui:order: + - includeName + - lastName + - includeAddress + - address + properties: + includeName: + title: Include Name? + type: boolean + default: true + includeAddress: + title: Include Address? + type: boolean + default: true + dependencies: + includeName: + allOf: + - if: + properties: + includeName: + const: true + then: + properties: + lastName: + title: Name + type: string + required: + - lastName + includeAddress: + allOf: + - if: + properties: + includeAddress: + const: true + then: + properties: + address: + title: Address + type: string + required: + - address +``` + ## Conditionally set parameters The `if` keyword within the parameter uses [nunjucks templating](https://mozilla.github.io/nunjucks/templating.html#if). The `not` keyword is unavailable; instead, use javascript equality. diff --git a/docs/features/software-templates/writing-custom-actions.md b/docs/features/software-templates/writing-custom-actions.md index 00a171523c..11e67af07f 100644 --- a/docs/features/software-templates/writing-custom-actions.md +++ b/docs/features/software-templates/writing-custom-actions.md @@ -141,6 +141,39 @@ Prefer to use `camelCase` over `snake_case` or `kebab-case` for these actions if > We're aware that there are some exceptions to this, but try to follow as close as possible. We'll be working on migrating these in the repository over time too. +### Adding a TemplateExample + +A TemplateExample is a predefined structure that can be used to create custom actions in your software templates. It serves as a blueprint for users to understand how to use a specific action and its fields as well as to ensure consistency and standardization across different custom actions. + +#### Define a TemplateExample and add to your Custom Action + +```ts title="With JSON Schema" +import { TemplateExample } from '@backstage/plugin-scaffolder-node'; +import yaml from 'yaml'; + +export const examples: TemplateExample[] = [ + { + description: 'Template Example for Creating an Acme file', + example: yaml.stringify({ + steps: [ + { + action: 'acme:file:create', + name: 'Create an Acme file.', + input: { + contents: 'file contents...', + filename: 'ACME.properties', + }, + }, + ], + }), + }, +]; +``` + +Add the example to the `createTemplateAction` under the object property `examples`: + +`return createTemplateAction<{ contents: string; filename: string }>({id: 'acme:file:create', description: 'Create an Acme file', examples, ...};` + ### The context object When the action `handler` is called, we provide you a `context` as the only diff --git a/docs/features/techdocs/addons.md b/docs/features/techdocs/addons.md index 471e62a57f..fff1f09d71 100644 --- a/docs/features/techdocs/addons.md +++ b/docs/features/techdocs/addons.md @@ -186,7 +186,7 @@ import { useShadowRootElements } from '@backstage/plugin-techdocs-react'; // difference is that you'd set `location` to `TechDocsAddonLocations.Content`. export const MakeAllImagesCatGifsAddon = () => { // This hook can be used to get references to specific elements. If you need - // access to the whole shadow DOM, use the the underlying useShadowRoot() + // access to the whole shadow DOM, use the underlying useShadowRoot() // hook instead. const images = useShadowRootElements(['img']); diff --git a/docs/features/techdocs/getting-started.md b/docs/features/techdocs/getting-started.md index 66772c861d..2c365bb5b9 100644 --- a/docs/features/techdocs/getting-started.md +++ b/docs/features/techdocs/getting-started.md @@ -297,7 +297,9 @@ You can do so by including the following lines right above `USER node` of your `Dockerfile`: ```Dockerfile -RUN apt-get update && apt-get install -y python3 python3-pip python3-venv +RUN apt-get update && \ + apt-get install -y python3 python3-pip python3-venv && \ + rm -rf /var/lib/apt/lists/* ENV VIRTUAL_ENV=/opt/venv RUN python3 -m venv $VIRTUAL_ENV diff --git a/docs/frontend-system/building-apps/06-plugin-conversion.md b/docs/frontend-system/building-apps/06-plugin-conversion.md index 5e7d431e73..2fab6cf828 100644 --- a/docs/frontend-system/building-apps/06-plugin-conversion.md +++ b/docs/frontend-system/building-apps/06-plugin-conversion.md @@ -58,7 +58,7 @@ The following are the known conversion functions provided by various libraries: ## Putting it all together -Using the plugin converter along with extension converters from various libraries, we can not more fully convert our 3rd-party plugin to be able to install it in an app built with the new frontend system: +Using the plugin converter along with extension converters from various libraries, we can now more fully convert our 3rd-party plugin to be able to install it in an app built with the new frontend system: ```ts import { diff --git a/docs/getting-started/concepts.md b/docs/getting-started/concepts.md deleted file mode 100644 index f8aba8537d..0000000000 --- a/docs/getting-started/concepts.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -id: concepts -title: Key Concepts -# prettier-ignore -description: High level key concepts used in the Backstage project ---- - -For users of Backstage, there are certain concepts which are central to its -design and functionality. Being an expert in each of these concepts is not -necessary, however having a base understanding of each will make administering, -configuring, and operating Backstage easier. - -- CHANGELOG - https://keepachangelog.com -- Docker - https://www.docker.com/ -- Monorepo - https://semaphoreci.com/blog/what-is-monorepo -- Node.js - https://nodejs.org -- React - https://reactjs.org -- Semantic Versioning - https://semver.org -- TypeScript - https://www.typescriptlang.org -- YAML - https://yaml.org -- Yarn - https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js diff --git a/docs/getting-started/config/database.md b/docs/getting-started/config/database.md index 0fbd66d5a3..699160d550 100644 --- a/docs/getting-started/config/database.md +++ b/docs/getting-started/config/database.md @@ -6,13 +6,13 @@ description: How to set up PostgreSQL for your Backstage instance. Audience: Admins -### Summary +## Summary -This guide walks through how to set up a PostgreSQL database to host your Backstage data. It assumes you've already have a scaffolded Backstage app from following the [Standalone Install](../index.md) guide. +This guide walks through how to set up a PostgreSQL database to host your Backstage data. It assumes you've already have a scaffolded Backstage app from following the [Creating your Backstage App](../index.md) guide. By the end of this tutorial, you will have a working PostgreSQL database hooked up to your Backstage install. -### Prerequisites +## Prerequisites This guide assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `apt-get`, `psql`, `yarn`. @@ -23,7 +23,7 @@ This guide assumes a basic understanding of working on a Linux based operating s - If the database is not hosted on the same server as the Backstage app, the PostgreSQL port needs to be accessible (the default is `5432` or `5433`) -### 1. Install and configure PostgreSQL +## 1. Install and Configure PostgreSQL :::tip Already configured your database? @@ -68,17 +68,9 @@ That's enough database administration to get started. Type `\q`, followed by pressing the enter key. Then again type `exit` and press enter. Next, you need to install and configure the client. -### 2. Configuring Backstage `pg` Client +## 2. Configuring Backstage `pg` Client -Go to the root directory of your freshly installed Backstage -App. Run the following to install the PostgreSQL client into your backend: - -```bash title="From your Backstage root directory" -yarn --cwd packages/backend add pg -``` - -Use your favorite editor to open `app-config.yaml` and add your PostgreSQL -configuration in the root directory of your Backstage app using the credentials from the previous steps. +Use your favorite editor to open `app-config.yaml` and add your PostgreSQL configuration in the root directory of your Backstage app using the credentials from the previous steps. ```yaml title="app-config.yaml" backend: @@ -126,6 +118,47 @@ After the Backstage frontend launches, you should notice that nothing has change We've now made your data persist in your Backstage database. +## Alternatives + +You may not want to install Postgres locally, the following sections outline alternatives. + +### Docker + +You can run Postgres in a Docker container, this is great for local development or getting a Backstage POC up and running quickly, here's how: + +First we need to pull down the container image, we'll use Postgres 17, check out the [Postgres Version Policy](../../overview/versioning-policy.md#postgresql-releases) to learn which versions are supported. + +```shell +docker pull postgres:17.0-bookworm +``` + +Then we just need to start up the container. + +```shell +docker run -d --name postgres --restart=always -p 5432:5432 -e POSTGRES_PASSWORD= postgres:17.0-bookworm +``` + +This will run Postgres in the background for you, but remember to start it up again when you reboot your system. + +### Docker Compose + +Another way to run Postgres is to use Docker Compose, here's what that would look like: + +```yaml title="docker-compose.local.yaml" +version: '4' + +services: + postgres: + image: postgres:17.0-bookworm + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: + ports: + - 5432:5432 +``` + +Then you would just run `docker compose -f docker-compose.local.yaml up` to start Postgres. + ## Next Steps We recommend you read [Setting up authentication](./authentication.md) next. @@ -136,3 +169,4 @@ If you want to read more about the database configuration, here are some helpful - [Configuring Plugin Databases](../../tutorials/configuring-plugin-databases.md#privileges) - [Read more about Knex](http://knexjs.org/), the database wrapper that we use. +- [Install `pgAdmin` 4](https://www.pgadmin.org/), a helpful tool for querying your database. diff --git a/docs/getting-started/configure-app-with-plugins.md b/docs/getting-started/configure-app-with-plugins.md index 95fd456dc0..c31cdc0a06 100644 --- a/docs/getting-started/configure-app-with-plugins.md +++ b/docs/getting-started/configure-app-with-plugins.md @@ -4,6 +4,14 @@ title: Configuring App with plugins description: Documentation on How Configuring App with plugins --- +Audience: Developers + +:::note Note +Backstage plugins are primarily written using [TypeScript](https://www.typescriptlang.org), [Node.js](https://nodejs.org) and [React](https://reactjs.org). Having an understanding of these technologies will be beneficial on your journey to customizing Backstage! +::: + +## Summary + Backstage plugins customize the app for your needs. There is a [plugin directory](https://backstage.io/plugins) with plugins for many common infrastructure needs - CI/CD, monitoring, auditing, and more. diff --git a/docs/getting-started/index.md b/docs/getting-started/index.md index 993cd7cbfd..687cf0be16 100644 --- a/docs/getting-started/index.md +++ b/docs/getting-started/index.md @@ -7,6 +7,10 @@ description: How to install Backstage for your own use. Audience: Developers and Admins +:::note Note +It is not required, although recommended to have a basic understanding of [Yarn](https://www.pluralsight.com/guides/yarn-a-package-manager-for-node-js) and [npm](https://docs.npmjs.com/about-npm) before starting this guide. +::: + ## Summary This guide walks through how to get started creating your very own Backstage customizable app. This is the first step in evaluating, developing on, or demoing Backstage. @@ -21,7 +25,7 @@ If you are planning to contribute a new feature or bug fix to the Backstage proj ## Prerequisites -This guide assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`. +This guide also assumes a basic understanding of working on a Linux based operating system and have some experience with the terminal, specifically, these commands: `npm`, `yarn`. - Access to a Unix-based operating system, such as Linux, macOS or [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) @@ -30,7 +34,7 @@ This guide assumes a basic understanding of working on a Linux based operating s On macOS, you will want to have run `xcode-select --install` to get the XCode command line build tooling in place. - An account with elevated rights to install the dependencies - `curl` or `wget` installed -- Node.js [Active LTS Release](https://nodejs.org/en/about/previous-releases) installed using one of these +- Node.js [Active LTS Release](../overview/versioning-policy.md#nodejs-releases) installed using one of these methods: - Using `nvm` (recommended) - [Installing nvm](https://github.com/nvm-sh/nvm#install--update-script) diff --git a/docs/getting-started/keeping-backstage-updated.md b/docs/getting-started/keeping-backstage-updated.md index 08b89db518..a811a33383 100644 --- a/docs/getting-started/keeping-backstage-updated.md +++ b/docs/getting-started/keeping-backstage-updated.md @@ -4,46 +4,19 @@ title: Keeping Backstage Updated description: How to keep your Backstage App updated --- +Audience: Developers and Admins + +:::note Note +To better understand the concepts in this section, it's recommended to have an understanding of [Monorepos](https://semaphoreci.com/blog/what-is-monorepo), [Semantic Versioning](https://semver.org) and [CHANGELOGs](https://keepachangelog.com). +::: + +## Summary + Backstage is always improving, so it's a good idea to stay in sync with the latest releases. Backstage is more of a library than an application or service; similar to `create-react-app`, the `@backstage/create-app` tool gives you a starting point that's meant to be evolved. -## Managing package versions with the Backstage yarn plugin - -The Backstage yarn plugin makes it easier to manage Backstage package versions, -by determining the appropriate version for each package based on the overall -Backstage version in backstage.json. This avoids the need to update every -package.json across your Backstage monorepo, and means that when adding new -`@backstage` dependencies, you don't need to worry about figuring out the right -version to use to match the currently-installed release of Backstage. - -### Requirements - -In order to use the yarn plugin, you'll need to be using yarn 4.1.1 or greater. - -### Installation - -To install the yarn plugin, run the following command in your Backstage -monorepo: - -```bash -yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin -``` - -The resulting changes in the file system should be committed to your repo. - -### Usage - -When the yarn plugin is installed, versions for currently-released `@backstage` -packages can be replaced in package.json with the string `"backstage:^"`. This -instructs yarn to resolve the version based on the overall Backstage version in -backstage.json. - -The `backstage-cli versions:bump` command documented below will detect the -installation of the yarn plugin, and when it's installed, will automatically -migrate dependencies across the monorepo to use it. - ## Updating Backstage versions with backstage-cli The Backstage CLI has a command to bump all `@backstage` packages and @@ -57,6 +30,12 @@ yarn backstage-cli versions:bump The reason for bumping all `@backstage` packages at once is to maintain the dependencies that they have between each other. +:::tip + +To make the version bump process even easier and more streamlined we highly recommend using the [Backstage yarn plugin](#managing-package-versions-with-the-backstage-yarn-plugin) + +::: + By default the bump command will upgrade `@backstage` packages to the latest `main` release line which is released monthly. For those in a hurry that want to track the `next` release line which releases weekly can do so using the `--release next` option. ```bash @@ -87,6 +66,53 @@ for any applicable updates when upgrading packages. As an alternative, the a consolidated view of all the changes between two versions of Backstage. You can find the current version of your Backstage installation in `backstage.json`. +## Managing package versions with the Backstage yarn plugin + +The Backstage yarn plugin makes it easier to manage Backstage package versions, +by determining the appropriate version for each package based on the overall +Backstage version in `backstage.json`. This avoids the need to update every +package.json across your Backstage monorepo, and means that when adding new +`@backstage` dependencies, you don't need to worry about figuring out the right +version to use to match the currently-installed release of Backstage. + +### Requirements + +In order to use the yarn plugin, you'll need to be using yarn 4.1.1 or greater. + +### Installation + +To install the yarn plugin, run the following command in your Backstage +monorepo: + +```bash +yarn plugin import https://versions.backstage.io/v1/tags/main/yarn-plugin +``` + +The resulting changes in the file system should be committed to your repo. + +:::tip + +For best results it's ideal to add the Backstage Yarn plugin when you are about to do a Backstage upgrade as it will make it easier to confirm everything is working. + +::: + +### Usage + +When the yarn plugin is installed, versions for currently-released `@backstage` +packages can be replaced in package.json with the string `"backstage:^"`. This +instructs yarn to resolve the version based on the overall Backstage version in +`backstage.json`. + +:::tip + +The `backstage.json` is key for the plugin to work, make sure this file is included in your CI/CD pipelines and/or any Container builds. + +::: + +The `backstage-cli versions:bump` command documented above will detect the +installation of the yarn plugin, and when it's installed, will automatically +migrate dependencies across the monorepo to use it. + ## More information on dependency mismatches Backstage is structured as a monorepo with diff --git a/docs/getting-started/register-a-component.md b/docs/getting-started/register-a-component.md index c935d25807..4e2076ee8d 100644 --- a/docs/getting-started/register-a-component.md +++ b/docs/getting-started/register-a-component.md @@ -6,6 +6,10 @@ description: Start populating your Backstage app with your data. Audience: Developers +:::note Note +Entity files are stored in YAML format, if you are not familiar with YAML, you can learn more about it [here](https://yaml.org). +::: + ## Summary This guide will walk you through how to pull Backstage data from other locations manually. There are integrations that will automatically do this for you. diff --git a/docs/integrations/azure-blobStorage/discovery.md b/docs/integrations/azure-blobStorage/discovery.md new file mode 100644 index 0000000000..32612daf75 --- /dev/null +++ b/docs/integrations/azure-blobStorage/discovery.md @@ -0,0 +1,76 @@ +--- +id: discovery +title: Azure Blob Storage Discovery +sidebar_label: Discovery +# prettier-ignore +description: Automatically discovering catalog entities from an Azure Blob Storage account +--- + +:::info +This documentation is written for [the new backend system](../../backend-system/index.md) which is the default since Backstage [version 1.24](../../releases/v1.24.0.md). +::: + +The Azure Blob Storage account integration has a special entity provider for discovering catalog +entities located in a storage account container. If you have a container that contains multiple +catalog files, and you want to automatically discover them, you can use this +provider. The provider will crawl your Blob Storage account container and register entities +matching the configured path. This can be useful as an alternative to static +locations or manually adding things to the catalog. + +To use the entity provider, you'll need an Azure Blob Storage account integration +[set up](locations.md) with `accountName` and either `aadCredential`, `sasToken`, or `accountKey` + +At production deployments, you likely manage these with the permissions attached +to your instance. + +In your configuration, you add a provider config per bucket: + +```yaml +# app-config.yaml + +catalog: + providers: + azureBlob: + providerId: + accountName: ${ACCOUNT_NAME} + containerName: ${CONTAINER_NAME} + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } +``` + +For simple setups, you can omit the provider ID at the config +which has the same effect as using `default` for it. + +```yaml +# app-config.yaml + +catalog: + providers: + azureBlob: + accountName: ${ACCOUNT_NAME} + containerName: ${CONTAINER_NAME} + schedule: # same options as in TaskScheduleDefinition + # supports cron, ISO duration, "human duration" as used in code + frequency: { minutes: 30 } + # supports ISO duration, "human duration" as used in code + timeout: { minutes: 3 } +``` + +As this provider is not one of the default providers, you will first need to install +the Azure catalog plugin: + +```bash title="From your Backstage root directory" +yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-azure +``` + +Then updated your backend by adding the following line: + +```ts title="packages/backend/src/index.ts" +backend.add(import('@backstage/plugin-catalog-backend')); +/* highlight-add-start */ +backend.add(import('@backstage/plugin-catalog-backend-module-azure')); +/* highlight-add-end */ +``` diff --git a/docs/integrations/azure-blobStorage/locations.md b/docs/integrations/azure-blobStorage/locations.md new file mode 100644 index 0000000000..38d8555c2e --- /dev/null +++ b/docs/integrations/azure-blobStorage/locations.md @@ -0,0 +1,51 @@ +--- +id: locations +sidebar_label: Locations +title: Azure Blob Storage account Locations +# prettier-ignore +description: Setting up an integration with Azure Blob Storage account +--- + +The Azure Blob Storage account integration supports loading catalog entities from an blob storage account container. +Entities can be added to +[static catalog configuration](../../features/software-catalog/configuration.md), +or registered with the +[catalog-import](https://github.com/backstage/backstage/tree/master/plugins/catalog-import) +plugin. + +## Configuration + +To use this integration, add configuration to your `app-config.yaml`: + +Using Azure active directory credentials: + +```yaml +integrations: + azureBlobStorage: + - accountName: ${ACCOUNT_NAME} # required + endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken + aadCredential: + clientId: ${CLIENT_ID} + tenantId: ${TENANT_ID} + clientSecret: ${CLIENT_SECRET} +``` + +Using Azure storage account SAS token: + +```yaml +integrations: + azureBlobStorage: + - accountName: ${ACCOUNT_NAME} # required + endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken + sasToken: ${SAS_TOKEN} +``` + +Using Azure storage account access key: + +```yaml +integrations: + azureBlobStorage: + - accountName: ${ACCOUNT_NAME} # required + endpoint: ${CUSTOM_ENDPOINT} # custom endpoint will require either aadCredentials or sasToken + accountKey: ${ACCOUNT_KEY} +``` diff --git a/docs/integrations/gitlab/org.md b/docs/integrations/gitlab/org.md index 66ce117aa0..8249a97c24 100644 --- a/docs/integrations/gitlab/org.md +++ b/docs/integrations/gitlab/org.md @@ -170,7 +170,7 @@ catalog: yourProviderId: host: gitlab.com orgEnabled: true - group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped) + group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only this group and groups under the provided path (which will be stripped) relations: # Optional - INHERITED # Optional. Members of any ancestor groups will also be considered members of the current group. - DESCENDANTS # Optional. Members of any descendant groups will also be considered members of the current group. @@ -240,7 +240,7 @@ catalog: yourProviderId: host: gitlab.com ## Could also be self hosted. orgEnabled: true - group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only groups under the provided path (which will be stripped) + group: org/teams # Required for gitlab.com when `orgEnabled: true`. Optional for self managed. Must not end with slash. Accepts only this group and groups under the provided path (which will be stripped) restrictUsersToGroup: true # Optional: Backstage will ingest only users directly assigned to org/teams. includeUsersWithoutSeat: false # Optional: Set to true to include users without paid seat, only applicable for SaaS ``` diff --git a/docs/notifications/index.md b/docs/notifications/index.md index b44b04ef4e..bb8a7dc246 100644 --- a/docs/notifications/index.md +++ b/docs/notifications/index.md @@ -385,7 +385,7 @@ Refer to the [service-to-service auth documentation](https://backstage.io/docs/a An example request for creating a broadcast notification might look like: ```bash -curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}' +curl -X POST https://[BACKSTAGE_BACKEND]/api/notifications/notifications -H "Content-Type: application/json" -H "Authorization: Bearer YOUR_BASE64_SHARED_KEY_TOKEN" -d '{"recipients":{"type":"broadcast"},"payload": {"title": "Title of broadcast message","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}' ``` ## Additional info diff --git a/docs/overview/adopting.md b/docs/overview/adopting.md index 5b6c3bcaed..a6053d0f85 100644 --- a/docs/overview/adopting.md +++ b/docs/overview/adopting.md @@ -94,31 +94,31 @@ Examples of tactics we have used to evangelize Backstage internally: These are some of the metrics that you can use to verify if Backstage has a successful impact on your software development process: -- **Onboarding time** Time until new engineers are productive. At Spotify we +- **Onboarding time** - Time until new engineers are productive. At Spotify we measure this as the time until the employee has merged their 10th PR (this metric was down 55% two years after deploying Backstage). Even though you may not be onboarding engineers at a rapid pace, this metric is a great proxy for the overall complexity of your ecosystem. Reducing it will therefore benefit your whole engineering organization, not just new joiners. -- **Number of merges per developer/day** Less time spent jumping between +- **Number of merges per developer/day** - Less time spent jumping between different tools and looking for information means more time to focus on shipping code. A second level of bottlenecks can be identified if you categorize contributions by domain (services, web, data, etc). -- **Deploys to production** Cousin to the metric above: How many times does an +- **Deploys to production** - Cousin to the metric above: How many times does an engineer push changes into production. -- **MTTR** With clear ownership of all the pieces in your microservices +- **MTTR** - With clear ownership of all the pieces in your microservices ecosystem and all tools integrated into one place, Backstage makes it quicker for teams to find the root cause of failures, and fix them. -- **Context switching** Reducing context switching can help engineers stay in +- **Context switching** - Reducing context switching can help engineers stay in the "zone". We measure the number of different tools an engineer has to interact with in order to get a certain job done (e.g. push a change, follow it into production and validate it did not break anything). -- **T-shapedness** A +- **T-shapedness** - A [T-shaped](https://medium.com/@jchyip/why-t-shaped-people-e8706198e437) engineer is someone that is able to contribute to different domains of engineering. Teams with T-shaped people have fewer bottlenecks and can @@ -126,10 +126,10 @@ successful impact on your software development process: since tools and infrastructure are consistent between domains, and information is available centrally. -- **eNPS** Surveys asking about how productive people feel, how easy it is to +- **eNPS** - Surveys asking about how productive people feel, how easy it is to find information and overall satisfaction with internal tools. -- **Fragmentation** _(Experimental)_ Backstage +- **Fragmentation** _(Experimental)_ - Backstage [Software Templates](../features/software-templates/index.md) help drive standardization in your software ecosystem. By measuring the variance in technology between different software components it is possible to get a sense diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index 2295a3e503..c745719e08 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -323,11 +323,8 @@ backend: cache: store: redis connection: redis://user:pass@cache.example.com:6379 - useRedisSets: true ``` -The useRedisSets flag is explained [here](https://github.com/jaredwray/keyv/tree/main/packages/redis#useredissets). - Contributions supporting other cache stores are welcome! ## Containerization diff --git a/docs/overview/versioning-policy.md b/docs/overview/versioning-policy.md index 2ae73e1383..f5e2e222f8 100644 --- a/docs/overview/versioning-policy.md +++ b/docs/overview/versioning-policy.md @@ -177,6 +177,8 @@ When we say _Supporting_ a Node.js release, that means the following: - New Backstage projects created with `@backstage/create-app` will have their `engines.node` version set accordingly. - Dropping compatibility with unsupported releases is not considered a breaking change. This includes using new syntax or APIs, as well as bumping dependencies that drop support for these versions. +Based on the above Backstage supports Node.js 20 and 22 as of the `1.33.0` release. + ## TypeScript Releases The Backstage project uses [TypeScript](https://www.typescriptlang.org/) for type checking within the project, as well as external APIs and documentation. It is important to have a clear policy for which TypeScript versions we support, since we want to be able to adopt new TypeScript features, but at the same time not break existing projects that are using older versions. diff --git a/docs/plugins/integrating-search-into-plugins.md b/docs/plugins/integrating-search-into-plugins.md index 05d07feb08..e51b4cfefa 100644 --- a/docs/plugins/integrating-search-into-plugins.md +++ b/docs/plugins/integrating-search-into-plugins.md @@ -106,15 +106,12 @@ Imagine your FAQs can be retrieved at the URL `https://backstage.example.biz/faq Below we provide an example implementation of how the FAQ collator factory could look like using our new document type, placed in the `plugins/search-backend-module-faq-snippets-collator/src/factory.ts` file: ```ts -import fetch from 'node-fetch'; import { Readable } from 'stream'; - import { LoggerService, RootConfigService, } from '@backstage/backend-plugin-api'; import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; - import { FaqSnippetDocument } from './types'; const DEFAULT_BASE_URL = 'https://backstage.example.biz/faq-snippets'; diff --git a/docs/releases/v1.33.0-changelog.md b/docs/releases/v1.33.0-changelog.md new file mode 100644 index 0000000000..f8c9c17aeb --- /dev/null +++ b/docs/releases/v1.33.0-changelog.md @@ -0,0 +1,2659 @@ +# Release v1.33.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.33.0](https://backstage.github.io/upgrade-helper/?to=1.33.0) + +## @backstage/backend-dynamic-feature-service@0.5.0 + +### Minor Changes + +- e939cd7: **BREAKING** The `dynamicPluginsFeatureLoader` options related to the root logger behavior (`transports`, `level`, `format`) are now gathered under a single `logger` option which is a function taking an optional `Config` argument and returning the logger options. + + This breaking change is required for 2 reasons: + + - it's totally possible that the current `Config` would be required to provide the logger options, + - the logger-related options should be gathered under a common `logger` option because, when the root auditing service is introduced, distinct but similarly-named options would be required for the auditor as well. + +### Patch Changes + +- 1aeec12: Enhance the `CommonJSModuleLoader` to add support for `resolvePackagePath` calls from backend dynamic plugins, with customizable package resolution, and make the `CommonJSModuleLoader` public API. + Fixing this backend dynamic plugin limitation related to `resolvePackagePath` is important for backend dynamic plugins which use the database, since database migration scripts systematically use `resolvePackagePath`. +- 8593dfa: Improve the way alpha packages are supported when loading dynamic backend plugins. + The `ScannedPluginPackage` descriptor of dynamic backend plugins loaded from their alpha `package.json` now contain both the main package manifest and the alpha manifest. Previously it used to contain only the content of the alpha `package.json`, which is nearly empty. + This will make it easier to use or display metadata of loaded dynamic backend plugins, which is contained in the main manifest. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/plugin-app-node@0.1.27 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/backend-openapi-utils@0.3.0 + +### Minor Changes + +- 1440232: Adds a new `createValidatedOpenApiRouterFromGeneratedEndpointMap` function that uses the new static server generation in `backstage-cli package schema openapi generate --server` to create a typed express router. + +### Patch Changes + +- f01787a: Moves msw from dependencies to devDependencies +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/backend-test-utils@1.1.0 + +### Minor Changes + +- 5064827: Made it possible to construct `mockServices.database` with a given knex instance + +### Patch Changes + +- 7aae8e3: The `mockServices.discovery.factory()` factory now uses the mocked discovery service as its implementation, avoid the need for configuration. +- eb82994: Removed unused `msw` dependency. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/catalog-client@1.8.0 + +### Minor Changes + +- 656d1ef: Internal update to use the updated generated code from `backstage-cli package schema openapi generate --client-package ...`. +- 31c4fe0: The client now automatically splits up very large `getEntitiesByRefs` calls into several smaller requests behind the scenes when needed. This ensures that each individual request does not exceed common Express.js request body limits or overload the server. + +### Patch Changes + +- 873f89a: Fix for certain filter fields in the `catalogApiMock` being case sensitive. +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/cli@0.29.0 + +### Minor Changes + +- bc47b17: **BREAKING**: Updates ESLint config to ignore all generated source code under `src/**/generated/**/*.ts`. + +- 6819f8c: Added a new optimization to the `repo test` command that will filter out unused packages in watch mode if all provide filters are paths that point from the repo root. This significantly speeds up running individual tests from the repo root in a large workspace, for example: + + ```sh + yarn test packages/app/src/App.test.tsx + ``` + +- d849865: The package packing now populates `typesVersions` for additional entry points rather than using additional `package.json` files for type resolution. This improves auto completion of separate entry points when consuming published packages. + +- bc71665: **BREAKING**: The `LEGACY_BACKEND_START` flag has been removed, along with support for `src/run.ts` as the development entry point. + +### Patch Changes + +- 4046d53: Fixed an issue where the `--successCache` option for the `repo test` and `repo lint` commands would be include the workspace path in generated cache keys. This previously broke caching in environments where the workspace path varies across builds. + +- 4a378d3: Fix dev server reloads of plugin discovery for new frontend system. + +- 28b60ad: The check for `react-dom/client` in the Jest configuration will now properly always run from the target directory. + +- 6b2888c: Fixed an issue with the `--successCache` flag for `repo test` where the tree hash for the wrong package directory would sometimes be used to generate the cache key. + +- e30b65d: Added `--alwaysPack` as a replacement for the now hidden `--alwaysYarnPack` flag for the `build-workspace` command. + +- be0278e: Removed circular import + +- a7f97e4: Added a new `"rejectFrontendNetworkRequests"` configuration flag that can be set in the `"jest"` field in the root `package.json`: + + ```json + { + "jest": { + "rejectFrontendNetworkRequests": true + } + } + ``` + + This flag causes rejection of any form of network requests that are attempted to be made in frontend or common package tests. This flag can only be set in the root `package.json` and can not be overridden in individual package configurations. + +- 6c48ebd: Add `--max-warnings -1` support to `backstage-cli package lint` + +- 04297a0: The `--successCache` option for the `repo test` and `repo lint` commands now use an additive store that keeps old entries around for a week before they are cleaned up automatically. + +- a2f0559: When using the experimental Rspack flag the app build and dev server now injects configuration via a `` tag in `index.html` rather than the `process.env.APP_CONFIG` definition, which will now be defined as an empty array instead. + + This requires the app to be using the config loader from the 1.31 release of Backstage. Make sure your app is using at least that version if you are upgrading to this version of the CLI. + + If you have copied the implementation of the `defaultConfigLoader`, make sure to update it to the new implementation. In particular the config loader needs to be able to read configuration from `script` tags with the type `backstage.io/config`. + +- b4627f2: Fixed an issue where the `raw-loader` for loading HTML templates was not resolved from the context of the CLI package. + +- cd1ef2b: Updated dependency `vite` to `^5.0.0`. + +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. + +- b533056: Updated dependency `css-loader` to `^7.0.0`. + +- be008c3: Updated dependency `@module-federation/enhanced` to `^0.7.0`. + +- 6266ed3: Updated dependency `del` to `^8.0.0`. + +- 4046d53: Fixed an issue with the `repo lint` command where the cache key for the `--successCache` option would not properly ignore files that should be ignored according to `.eslintignore`s. + +- e19c53c: Fix for the `--link` flag for `package start` to deduplicate `react-router` and `react-router-dom`. + +- 17850a5: Update upgrade-helper link in `versions:bump` command to include `yarnPlugin` parameter when the yarn plugin is installed + +- 09ea093: Fixed an issue where `.css` style injection would fail for published packages. + +- 702f41d: Bumped dev dependencies `@types/node` + +- 5d74716: Remove unused backend-common dependency + +- b084f5a: Bump the Webpack dependency range to `^5.94.0`, as our current configuration is not compatible with some older versions. + +- e565f73: Added support for `.webp` files in the frontend tooling. + +- 946fa34: Added a new `--link ` option for frontend builds that allow you to override module resolution to link in an external workspace at runtime. + + As part of this change the Webpack linked workspace resolution plugin for frontend builds has been removed. It was in place to support the old workspace linking where it was done by Yarn, which is no longer a working option. + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.15.2 + - @backstage/release-manifests@0.0.11 + +## @backstage/config@1.3.0 + +### Minor Changes + +- d52d7f9: Make `readDurationFromConfig` support both ISO and ms formats as well, to make it easier to enter time as an end user + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + +## @backstage/core-components@0.16.0 + +### Minor Changes + +- dc409c5: The SupportButton component will now be hidden if no support config is specified in app-config + +### Patch Changes + +- 0f18340: Change core component Table tool bar search box to the a appropriate Search icon and text + +- af9097e: Adds the ability to mock a media query per break point and to change the active break point during a test. Usage example: + + ```ts + const { set } = mockBreakpoint({ + initialBreakpoint: 'md', + queryBreakpointMap: { + '(min-width:1500px)': 'xl', + '(min-width:1000px)': 'lg', + '(min-width:700px)': 'md', + '(min-width:400px)': 'sm', + '(min-width:0px)': 'xs', + }, + }); + // assertions for when the active break point is "md" + set('lg'); + // assertions for when the active break point is "lg" + ``` + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + +## @backstage/repo-tools@0.11.0 + +### Minor Changes + +- 1440232: `backstage-repo-tools package schema openapi generate --server` now generates complete TS interfaces for all request/response objects in your OpenAPI schema. This fixes an edge case around recursive schemas and standardizes both the generated client and server to have similar generated types. +- 47fdbb4: Adds a `--watch` mode to the `schema openapi generate` command for a better local schema writing experience. + +### Patch Changes + +- 95401a8: The `generate-patch` command now properly includes newly created files in the patch. +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. +- 3f1fb21: The `generate-patch` command will now fall back to always adding a `resolutions` entry, even if no matching descriptors are found. +- dde85ee: Added a new `generate-patch` command that can be used to generate patches for current changes in a source workspace to be installed it a target workspace. +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + +## @backstage/types@1.2.0 + +### Minor Changes + +- c5e39e7: Introduce `createDeferred` and `DeferredPromise`. + +## @backstage/plugin-api-docs@0.12.0 + +### Minor Changes + +- 6836522: Added support for pagination in api-docs plugin - DefaultApiExplorerPage + +### Patch Changes + +- 11f57de: bump `@asyncapi/react-component` to latest `2.x` +- 3cd1dee: Uses theme values to style the API definition schema so that theme overrides apply. +- Updated dependencies + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app-backend@0.4.0 + +### Minor Changes + +- 815b702: Configuration is no longer injected into static assets if a `index.html.tmpl` file is present. + +### Patch Changes + +- 815b702: The `index.html` templating is now done and served from memory rather than written to the filesystem. This means that you can now use config injection with a read-only filesystem, and you no longer need to use the `app.disableConfigInjection` flag. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-app-node@0.1.27 + +## @backstage/plugin-auth-backend@0.24.0 + +### Minor Changes + +- 75168e3: **BREAKING**: The AWS ALB `fullProfile` will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result. + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-auth-backend-module-google-provider@0.2.2 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.2 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.2 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.2 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.2 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.2 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.2 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.2 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.0 + +### Minor Changes + +- 75168e3: **BREAKING**: The AWS ALB `fullProfile` will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result. + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog@1.25.0 + +### Minor Changes + +- 50df3c8: - Updated EntityLayout component to implement breadcrumb navigation based on the entity relations. + + - Added parentEntityRelations prop to EntityLayoutProps to specify relation types for parent entities. + +- 79e9631: Allow `OffsetPaginatedCatalogTable` to configure Table options and `CursorPaginatedCatalogTable` to configure `paginationPosition`. + +### Patch Changes + +- 2a67594: Fixed an issue causing the `CatalogIndexPage` to not properly filter results when using offset pagination. +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + +## @backstage/plugin-catalog-backend@1.28.0 + +### Minor Changes + +- 39fd704: Internal update to use the new generated server types from `backstage-cli package schema openapi generate --server`. +- 76857da: Added `entity_ref` column to `final_entities` in order to move `refresh_state` away from the read path +- 34d4360: Drop redundant indices from the database. + + The following redundant indices are removed in this version: + + - `final_entities_entity_id_idx` - overlaps with `final_entities_pkey` + - `refresh_state_entity_id_idx` - overlaps with `refresh_state_pkey` + - `refresh_state_entity_ref_idx` - overlaps with `refresh_state_entity_ref_uniq` + - `search_key_idx` and `search_value_idx` - these were replaced by the composite index `search_key_value_idx` in #22594 + + No negative end user impact is expected, but rather that performance should increase due to less index churn. + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- b89834b: Fixed an issue where entities would not be marked for restitching if only the target of a relationship changed. +- 1bf02cc: Fixed bug when searching an entity by `spec.profile.displayName` in the catalog on the frontend. Text filter fields were not applied correctly to the database query resulting in empty results. +- 4e58bc7: Upgrade to uuid v11 internally +- 5efde17: Internal refactor to slightly speed up the processing loop +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-catalog-backend-module-gitlab@0.5.0 + +### Minor Changes + +- 1b5fdd9: Extended the configuration with the `includeArchivedRepos` property, which allows including repositories when the project is archived. + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.6.0 + +### Minor Changes + +- 6cf91c5: Use `HumanDuration` for all duration needs in the public API, instead of `luxon` types. These are generally compatible, with a few caveats: + + - If you scheduled things to run quarterly (`quarter` or `quarters`), you can use `{ months: 3 }` instead. + - If you used the singular nouns such as `year: 1`, use plurals instead (e.g. `years: 1`). + +### Patch Changes + +- c5e39e7: Internal refactor to use the deferred from the types package +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend-module-ldap@0.10.0 + +### Minor Changes + +- 415aeb3: Add Support for Google LDAP Vendor + +### Patch Changes + +- 884a86c: Added a `dnCaseSensitive` flag to support LDAP servers with mixed-case attributes. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-node@1.14.0 + +### Minor Changes + +- bc13b42: The `catalogServiceRef` now has its own accompanying `CatalogService` interface that requires Backstage `credentials` objects to be passed. This new version of the `catalogServiceRef` has been promoted and is now available via the main `@backstage/plugin-catalog-node` entry point. + + The old `catalogServiceRef` with the old `CatalogApi` type is still available from the `/alpha` entry point. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-kubernetes@0.12.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + +## @backstage/plugin-kubernetes-backend@0.19.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- bee9664: Adapted the config.d.ts for custom k8s cluster authProvider implementations +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-node@0.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-kubernetes-common@0.9.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-kubernetes-node@0.2.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-kubernetes-react@0.5.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- 0b729da: add the pod delete feature to the kubernetes react plugin +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-notifications@0.4.0 + +### Minor Changes + +- 87ffc1c: Rephrasing labels of the View filter to be more clear. Based on the received users' feedback. + +### Patch Changes + +- 4186105: Added title to the Notifications' table. The title clearly states the filter selection and total count of messages. This change aligns the look and feel closer to other tables. +- 3a0731e: The "Created after" filter renamed to the "Sent out" based on the received users' feedback. +- 3e135f2: The notification's title is emphasized to be clearly distinguished from the description. +- 97ba58f: Add support for user specific notification settings +- 1d87c43: Show count of unread notifications in the left-side MenuItem. This replaces the simple true/false bullet. +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-scaffolder@1.27.0 + +### Minor Changes + +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- 69fb6e7: Fix `contextMenu` not being disabled bug in new scaffolder pages + +### Patch Changes + +- 99471cd: fix(scaffolder): use `onInputChange` in `RepoUrlPicker` to fix issue with the value not updating properly +- 8e4bed4: Updated dependency `idb-keyval` to `5.1.5`. +- 7669af3: Revert the change of the option label for `EntityPicker` +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-scaffolder-backend@1.27.0 + +### Minor Changes + +- 0587633: Bumped the `isolated-vm` dependency from v4 to v5, which drops support for Node.js v16. +- e61d5ef: BREAKING EXPERIMENTAL: The `checkpoint` method now takes an object instead of previous arguments. + + ```ts + await ctx.checkpoint({ key: 'repo.create', fn: () => ockokit.repo.create({...})}) + ``` + + You can also now return `void` from the checkpoint if the method returns `void` inside the `checkpoint` handler. + +### Patch Changes + +- 6aa5b98: Fix tasks listing with postgres +- 59137ff: Fix issue with token not being available because it's now non-enumerable +- c5e39e7: Internal refactor to use the deferred from the types package +- e4f5d95: Align with type declaration of template filter/global function by supporting undefined as return value. +- d52d7f9: Support ISO and ms string forms of durations in config too +- 7ab3371: Modified `createDryRunner` and corresponding route to include `templateMetaData` inside the `templateInfo`. This allows custom action writers to access things like `templateInfo.entity.metadata.name` via the action context while executing templates using the dry run framework. +- 4e58bc7: Upgrade to uuid v11 internally +- 2dae341: Add new `fs:readdir` action to list current content of the workspace +- 97ba58f: Add example template for notification sending +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.6.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.2 + +## @backstage/plugin-scaffolder-node@0.6.0 + +### Minor Changes + +- e61d5ef: BREAKING EXPERIMENTAL: The `checkpoint` method now takes an object instead of previous arguments. + + ```ts + await ctx.checkpoint({ key: 'repo.create', fn: () => ockokit.repo.create({...})}) + ``` + + You can also now return `void` from the checkpoint if the method returns `void` inside the `checkpoint` handler. + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-react@1.14.0 + +### Minor Changes + +- 69fb6e7: Fix `contextMenu` not being disabled bug in new scaffolder pages + +### Patch Changes + +- 8b5ff7e: Fix issue with form state not refreshing when updating +- ade301c: Fix issue with `Stepper` and trying to trim additional properties. This is now all behind `liveOmit` and `omitExtraData` instead. +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-search-backend@1.7.0 + +### Minor Changes + +- 39fd704: Internal update to use the new generated server types from `backstage-cli package schema openapi generate --server`. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/app-defaults@1.5.13 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/backend-app-api@1.0.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/backend-defaults@0.5.3 + +### Patch Changes + +- bf306cb: Removed dependency `@backstage/backend-common`. +- e30bb46: Disabling database migrations now correctly uses the `backend.default.skipMigrations` config value. +- d52d7f9: Support ISO and ms string forms of durations in config too +- f6eaec2: Link to proper package in `rootLoggerServiceFactory` doc string. +- ecf6b39: Use `node-fetch` instead of native fetch, as per +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/backend-plugin-api@1.0.2 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @backstage/catalog-model@1.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + +## @backstage/cli-common@0.1.15 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` + +## @backstage/cli-node@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @backstage/codemods@0.1.52 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/config-loader@1.9.2 + +### Patch Changes + +- c5e39e7: Internal refactor to use the deferred from the types package +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @backstage/core-app-api@1.15.2 + +### Patch Changes + +- 44b82da: The default config loader no longer requires `process.env.APP_CONFIG` to be set, allowing config to be read from other sources instead. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-compat-api@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-plugin-api@1.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + +## @backstage/create-app@0.5.22 + +### Patch Changes + +- 7907e3b: Bumped create-app version. +- 42386c2: Bumped create-app version. +- 702f41d: Updated engines to support Node 20 or 22 +- a917f86: This update adds the @backstage/repo-tools package to the versions.ts file, enabling proper version resolution for templates. The {{version '@backstage/repo-tools'}} placeholder now works as expected in the create-app process. +- 5872964: Use the main entrypoint for `create-app` installs +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/dev-utils@1.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.1 + +## @backstage/errors@1.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + +## @backstage/frontend-app-api@0.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/core-app-api@1.15.2 + - @backstage/frontend-defaults@0.1.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-defaults@0.1.2 + +### Patch Changes + +- 44b82da: The default config loader no longer requires `process.env.APP_CONFIG` to be set, allowing config to be read from other sources instead. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-app@0.1.2 + +## @backstage/frontend-plugin-api@0.9.1 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-test-utils@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/test-utils@1.7.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.2 + +## @backstage/integration@1.15.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/integration-aws-node@0.1.13 + +### Patch Changes + +- 52ae92d: The `getDefaultCredentialsChain` function now accepts and applies a `region` parameter, preventing it from defaulting to `us-east-1` when no region is specified. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/integration-react@1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.15.2 + +## @techdocs/cli@1.8.22 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-techdocs-node@1.12.13 + +## @backstage/test-utils@1.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-app-api@1.15.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/theme@0.6.1 + +### Patch Changes + +- ea75c37: Internal refactor to avoid top-level imports from MUI. + +## @backstage/plugin-app@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app-node@0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-app-visualizer@0.1.12 + +### Patch Changes + +- e586e77: New `devDependency` for local development setup. +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.2 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-github-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-google-provider@0.2.2 + +### Patch Changes + +- b833660: Fix visibility of config for use in front end code +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.2 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.3.2 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-okta-provider@0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-auth-node@0.5.4 + +### Patch Changes + +- a0a9a4a: Browsers silently drop cookies that exceed 4KB, which can be problematic for refresh tokens and other large cookies.This update ensures that large cookies, like refresh tokens, are not dropped by browsers, maintaining the integrity of the authentication process. The changes include both the implementation of the cookie splitting logic and corresponding tests to validate the new functionality. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-react@0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-bitbucket-cloud-common@0.2.25 + +### Patch Changes + +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. +- Updated dependencies + - @backstage/integration@1.15.2 + +## @backstage/plugin-catalog-backend-module-aws@0.4.5 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-azure@0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.4.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- f6b4b8a: Implemented discovery on project-level to shift Bitbucket Cloud API limits +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-catalog-backend-module-gerrit@0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-catalog-backend-module-github@0.7.7 + +### Patch Changes + +- 9790c02: Fixed an issue in `GithubOrgEntityProvider` that caused an error when processing teams without a parent. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend-module-github@0.7.7 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.0 + +## @backstage/plugin-catalog-backend-module-logs@0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.6.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.4 + +### Patch Changes + +- 5f058e2: Updated dependency `@apidevtools/json-schema-ref-parser` to `^11.0.0`. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.5.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + +## @backstage/plugin-catalog-common@1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-catalog-graph@0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + +## @backstage/plugin-catalog-import@0.12.6 + +### Patch Changes + +- ea5b7f3: Fixed parsing of catalog-info.yaml when creating a PR to register a repository if the file contains more than one document +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-react@1.14.1 + +### Patch Changes + +- 9cc82c0: Fixed bug in `EntityDisplayName` where text was overflowing. +- 6fcbb3b: Ensure EntityDisplayName component link receives underline on hover. +- 9670906: Improve UI consistency of default catalog filters +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/frontend-test-utils@0.2.2 + - @backstage/integration-react@1.2.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-config-schema@0.1.61 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-devtools@0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-devtools-backend@0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-devtools-common@0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-events-backend@0.3.16 + +### Patch Changes + +- e02a02b: Fix `events.useEventBus` by propagating config to `DefaultEventsService` +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. +- b7d0334: Cleaning up event subscriptions after the max age window +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.5 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-module-azure@0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-module-gerrit@0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-module-github@0.2.14 + +### Patch Changes + +- 9816f51: Fix the event request validation for incoming requests for GitHub webhook events + by using the raw body when verifying the signature. +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-module-gitlab@0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-events-backend-test-utils@0.1.38 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + +## @backstage/plugin-events-node@0.4.5 + +### Patch Changes + +- 4501631: Fixed an issue where subscribing to events threw an error and gave up too easily. Calling the subscribe method will cause the background polling loop to keep trying to connect to the events backend, even if the initial request fails. + + By default the events service will attempt to publish and subscribe to events from the events bus API in the events backend, but if it fails due to the events backend not being installed, it will bail and never try calling the API again. There is now a new `events.useEventBus` configuration and option for the `DefaultEventsService` that lets you control this behavior. You can set it to `'never'` to disabled API calls to the events backend completely, or `'always'` to never allow it to be disabled. + +- e02a02b: Fix `events.useEventBus` by propagating config to `DefaultEventsService` + +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. + +- 5d74716: Remove unused backend-common dependency + +- 0b57aa1: Fixed an issue where the event bus polling would duplicate and increase exponentially over time. + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-home@0.8.1 + +### Patch Changes + +- 8b1b2cf: Improve Starred Entities UI to reduce whitespace and provide more context on the entities: + + - Use the Entity Presentation API (via ``) to display the entity's name + - Component's `kind` and `spec.type` are displayed as a secondary text + - List items are condensed to reduce unnecessary spacing + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-home-react@0.1.19 + +## @backstage/plugin-home-react@0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-kubernetes-cluster@0.0.18 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-notifications-backend@0.4.3 + +### Patch Changes + +- 97ba58f: Add support for user specific notification settings +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-notifications-backend-module-email@0.3.3 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-notifications-common@0.0.6 + +### Patch Changes + +- 97ba58f: Add support for user specific notification settings +- Updated dependencies + - @backstage/config@1.3.0 + +## @backstage/plugin-notifications-node@0.2.9 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-org@0.6.32 + +### Patch Changes + +- a278fdd: Fix rendering of description in MembersListCard. Add guardrails for potential long texts to prevent it from breaking the UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-org-react@0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-permission-backend@0.5.51 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.5 + +## @backstage/plugin-permission-common@0.8.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-permission-node@0.8.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-permission-react@0.4.28 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-proxy-backend@0.5.8 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.2 + +### Patch Changes + +- 9cf827c: Fix double branch creation in `public:bitbucket{Cloud,Server}:pull-request` + This resulted in the following error when using the actions: + + AlreadyExistsError: Failed to create branch at create-test because it already exists. + + The issue was original introduced in d103a48fa306d745599dc0c793668c9e6a479d32 + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.2 + +### Patch Changes + +- 9cf827c: Fix double branch creation in `public:bitbucket{Cloud,Server}:pull-request` + This resulted in the following error when using the actions: + + AlreadyExistsError: Failed to create branch at create-test because it already exists. + + The issue was original introduced in d103a48fa306d745599dc0c793668c9e6a479d32 + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-github@0.5.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.6.1 + +### Patch Changes + +- cdc8b4c: Improve error messages from Gitlab +- 2dbdccb: Removed circular import +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/plugin-scaffolder-node@0.6.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.2 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.15 + +## @backstage/plugin-scaffolder-common@1.5.7 + +### Patch Changes + +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-test-utils@1.1.0 + - @backstage/plugin-scaffolder-node@0.6.0 + +## @backstage/plugin-search@1.4.19 + +### Patch Changes + +- a4ccc82: Removes the card UI from the search results type filter for a cleaner UI consistent with other filters +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + +## @backstage/plugin-search-backend-module-catalog@0.2.5 + +### Patch Changes + +- 0b8f344: Fixed a bug where the `filter` setting of the collator was not permitted to be an array. +- 1a1e2f4: Fix search collator text formatting for catalog entities without description +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-elasticsearch@1.6.2 + +### Patch Changes + +- dae59c1: Updated dependency `@short.io/opensearch-mock` to `^0.4.0`. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-explore@0.2.5 + +### Patch Changes + +- a9a7c7c: Updated dependency `@backstage-community/plugin-explore-common` to `^0.0.7`. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-pg@0.5.38 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-techdocs@0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-node@1.12.13 + +## @backstage/plugin-search-backend-node@1.3.5 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-common@1.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-search-react@1.8.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-signals@0.0.12 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-signals-backend@0.2.3 + +### Patch Changes + +- a1e01ff: The signals backend now supports scaled deployments where clients may be connecting to one of many signal backend instances. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-signals-node@0.1.14 + +## @backstage/plugin-signals-node@0.1.14 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + +## @backstage/plugin-signals-react@0.0.7 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-techdocs@1.11.1 + +### Patch Changes + +- 37a7810: Fixed an issue where `` would re-render infinitely under certain conditions. +- e937ae7: Fix an issue with index page of documentation site being re-rendered. +- 90246a9: Fix techdocs config schema for custom elements sanitizer +- 605bdc0: Avoid page re-rendering when clicking on anchor links in the same documentation page. +- 4f0cb89: Added DomPurify sanitizer configuration for custom elements implementing RFC . + See for how to enable it in the configuration. +- f246178: Removed `canvas` dev dependency. +- 4a2f73a: Fix an issue that caused the current documentation page to be re-rendered when navigating to + another one. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.41 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-app-api@1.15.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.1 + - @backstage/test-utils@1.7.1 + - @backstage/plugin-search-react@1.8.2 + +## @backstage/plugin-techdocs-backend@1.11.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.2 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-node@1.12.13 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + +## @backstage/plugin-techdocs-node@1.12.13 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-react@1.2.10 + +### Patch Changes + +- 4a2f73a: Fix an issue that caused the current documentation page to be re-rendered when navigating to + another one. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/plugin-user-settings@0.8.15 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/errors@1.2.5 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.103 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-api-docs@0.12.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-notifications@0.4.0 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/plugin-search@1.4.19 + - @backstage/plugin-org@0.6.32 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder@1.27.0 + - @backstage/plugin-catalog-import@0.12.6 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes@0.12.0 + - @backstage/plugin-home@0.8.1 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-app-api@1.15.2 + - @backstage/plugin-signals@0.0.12 + - @backstage/plugin-kubernetes-cluster@0.0.18 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.12 + - @backstage/plugin-catalog-unprocessed-entities@0.2.10 + - @backstage/plugin-devtools@0.1.20 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.17 + - @backstage/plugin-user-settings@0.8.15 + +## example-app-next@0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-api-docs@0.12.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-notifications@0.4.0 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/plugin-search@1.4.19 + - @backstage/plugin-org@0.6.32 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder@1.27.0 + - @backstage/plugin-catalog-import@0.12.6 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes@0.12.0 + - @backstage/plugin-home@0.8.1 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/plugin-app-visualizer@0.1.12 + - @backstage/core-app-api@1.15.2 + - @backstage/frontend-defaults@0.1.2 + - @backstage/plugin-signals@0.0.12 + - @backstage/plugin-kubernetes-cluster@0.0.18 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-app@0.1.2 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.12 + - @backstage/plugin-catalog-unprocessed-entities@0.2.10 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.17 + - @backstage/plugin-user-settings@0.8.15 + +## app-next-example-plugin@0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/frontend-plugin-api@0.9.1 + +## example-backend@0.0.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-app-backend@0.4.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-scaffolder-backend@1.27.0 + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-search-backend@1.7.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/plugin-kubernetes-backend@0.19.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-search-backend-module-explore@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.2.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-backend@0.4.3 + - @backstage/plugin-signals-backend@0.2.3 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-proxy-backend@0.5.8 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.3 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.2 + - @backstage/plugin-devtools-backend@0.4.2 + - @backstage/plugin-permission-backend@0.5.51 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.2 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-github@0.5.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.2 + - @backstage/plugin-techdocs-backend@1.11.2 + +## example-backend-legacy@0.2.104 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-app-backend@0.4.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-scaffolder-backend@1.27.0 + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-search-backend@1.7.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.6.1 + - @backstage/plugin-kubernetes-backend@0.19.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.2 + - @backstage/plugin-search-backend-module-explore@0.2.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-signals-backend@0.2.3 + - @backstage/plugin-search-backend-module-pg@0.5.38 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-proxy-backend@0.5.8 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.2 + - @backstage/plugin-devtools-backend@0.4.2 + - @backstage/plugin-permission-backend@0.5.51 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.2 + - @backstage/plugin-techdocs-backend@1.11.2 + +## e2e-test@0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.22 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @internal/frontend@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + +## @internal/scaffolder@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.0 + +## techdocs-cli-embedded-app@0.2.102 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-app-api@1.15.2 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.1 + - @backstage/test-utils@1.7.1 + +## yarn-plugin-backstage@0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/release-manifests@0.0.11 + +## @internal/plugin-todo-list@1.0.33 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + +## @internal/plugin-todo-list-backend@1.0.33 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + +## @internal/plugin-todo-list-common@1.0.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 diff --git a/docs/releases/v1.33.0.md b/docs/releases/v1.33.0.md new file mode 100644 index 0000000000..c8798ea9e5 --- /dev/null +++ b/docs/releases/v1.33.0.md @@ -0,0 +1,73 @@ +--- +id: v1.33.0 +title: v1.33.0 +description: Backstage Release v1.33.0 +--- + +These are the release notes for the v1.33.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 + +### Catalog performance improvements and breadcrumbs + +Some database improvements and fixes have been made to the catalog. The `refresh_state` table is no longer needed in the read path, and some indices have been dropped. We don't expect this to have any negative impact on end users; rather, performance should increase due to reduced index churn and less used storage. + +Entity pages now also by default have a breadcrumb control in the page header, showing the context of the current entity such as what system and domain it’s in, if any. + +### App backend config injection with read-only filesystem + +The `app-backend` now stores the templated `index.html` file in memory rather than writing it to disk. This means you no longer need to use the `app.disableConfigInjection` flag when running with a read-only filesystem, allowing you to take advantage of the config injection. + +### **BREAKING**: `LEGACY_BACKEND_START` has been removed + +The CLI no longer supports the `LEGACY_BACKEND_START` flag, which means that old dev endpoints in `src/run.ts` have to be migrated to the new `dev/index.ts` structure instead. + +### Scaffolder now supports Node.js v22 + +The `isolated-vm` dependency has been upgraded to `v5`, which means the scaffolder now supports Node.js v22. It also means that running Scaffolder with Node.js v16 is no longer possible. + +### Scaffolder permissions and actions + +A new `scaffolder.template.management` permission has been added. This permission is useful if you want to limit access to the frontend template management features. Contributed by [@stephenglass](https://github.com/stephenglass) in [#26946](https://github.com/backstage/backstage/pull/26946) + +A new `fs:readdir` action has been added. This action is useful if you need to retrieve the contents of a specific directory within a workspace. Contributed by [@secustor](https://github.com/secustor) in [#27283](https://github.com/backstage/backstage/pull/27283) + +### Catalog service ref for backends + +The `@backstage/plugin-catalog-node` package now has a `catalogServiceRef` that backends should move to depending on for their catalog communication needs. If you are currently instantiating a `CatalogService` by hand, you will enjoy using this new service instead. The most important improvement is that it supports a credentials argument directly which gives it support for proper auth toward the catalog without having to make tokens with the `auth` core service. + +### New generate-patch cli command + +We have added a new `generate-patch` CLI command that can be used to generate patches for current changes in a source workspace, which can then be installed in a target workspace. This allows you to easily and immediately use changes that have been contributed upstream, without needing to wait for a release. +[#27331](https://github.com/backstage/backstage/pull/27331) + +### Google LDAP support + +Added support for Google LDAP to `@backstage/plugin-catalog-backend-module-ldap`. Contributed by [@megatroom](https://github.com/megatroom) in [#27373](https://github.com/backstage/backstage/pull/27373) + +### **BREAKING** AWS ALB authentication + +The AWS ALB `fullProfile` will no longer have its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result via `@backstage/plugin-auth-backend-module-aws-alb-provider`. + +## Security Fixes + +The kubernetes plugin received a bump of the `@kubernetes/client-node` dependency to mitigate CVEs related to the `request` and `tough-cookie` packages. Contributed by [@coreydaley](https://github.com/coreydaley) in [#25385](https://github.com/backstage/backstage/pull/25385) + +## 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.33.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/releases/v1.34.0-next.0-changelog.md b/docs/releases/v1.34.0-next.0-changelog.md new file mode 100644 index 0000000000..4ed7a2a57b --- /dev/null +++ b/docs/releases/v1.34.0-next.0-changelog.md @@ -0,0 +1,2234 @@ +# Release v1.34.0-next.0 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.34.0-next.0](https://backstage.github.io/upgrade-helper/?to=1.34.0-next.0) + +## @backstage/backend-defaults@0.6.0-next.0 + +### Minor Changes + +- de6f280: **BREAKING** Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys. + + This is a breaking change for clients using the `redis` store for cache with `useRedisSets` option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore. + + If you were using `useRedisSets` option in configuration make sure to remove it from `app-config.yaml`: + + ```diff + backend: + cache: + store: redis + connection: redis://user:pass@cache.example.com:6379 + - useRedisSets: false + ``` + +- 277092a: Implemented `AzureBlobStorageUrlReader` to read from the url of committed location from the entity provider + +- 18a2c00: All middleware used by the default `coreServices.http` is now exported for use by custom implementations. + +### Patch Changes + +- 8863b38: Export `PluginTokenHandler` and `pluginTokenHandlerDecoratorServiceRef` to allow for custom decoration of the plugin token handler without having to re-implement the entire handler. +- 97c6837: Export `DefaultHttpAuthService` to allow for custom token extraction logic. +- e5255f1: Log request and response metadata so it can be used for filtering log messages. + The format of the request date was also changed from `clf` to `utc`. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/backend-test-utils@1.2.0-next.0 + +### Minor Changes + +- de6f280: **BREAKING** Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys. + + This is a breaking change for clients using the `redis` store for cache with `useRedisSets` option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore. + + If you were using `useRedisSets` option in configuration make sure to remove it from `app-config.yaml`: + + ```diff + backend: + cache: + store: redis + connection: redis://user:pass@cache.example.com:6379 + - useRedisSets: false + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/integration@1.16.0-next.0 + +### Minor Changes + +- 277092a: Add the integration for Azure blob storage to read the credentials to access the storage account and provide the default credential provider. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/repo-tools@0.12.0-next.0 + +### Minor Changes + +- c1eccd6: Fix invalid path and malformed flags bugs in api-reports.ts + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend-module-azure@0.3.0-next.0 + +### Minor Changes + +- 277092a: Added the Azure Blob Storage as catalog entity provider to import all the desired entities from storage account provided in app-config.yaml + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.11.0-next.0 + +### Minor Changes + +- 732700a: Updated fix for ldap entity mapping which doesn't require extra config setting of dnCaseSensitive +- 95ac4a2: Add new ldap vendor config 'LLDAP' + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-scaffolder-backend@1.28.0-next.0 + +### Minor Changes + +- c05a343: Emit scaffolder events using the optional `EventsService` + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- 8f59dc5: Add fs:readdir to scaffolder startup +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.4-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.5.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.0 + +### Minor Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 32459d0: **BREAKING**: Upgraded the `gitbeaker` library to version 41. As part of this, the `scopes` parameter to the `gitlab:projectDeployToken:create` is no longer optional, so you will have to pass it a value (for example `['read_repository']`). + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/app-defaults@1.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/backend-app-api@1.0.3-next.0 + +### Patch Changes + +- eef3ef1: Removed unused `express` dependencies. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/backend-dynamic-feature-service@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/backend-openapi-utils@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/backend-plugin-api@1.0.3-next.0 + +### Patch Changes + +- eef3ef1: Removed unused `express` dependencies. +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/catalog-client@1.8.1-next.0 + +### Patch Changes + +- d7e7836: Fixed a bug in the `queryEntities` method where errors were not being handled properly. +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/cli@0.29.3-next.0 + +### Patch Changes + +- 2b6c1ea: If the Backstage yarn plugin is installed, it will now be automatically updated as part of `versions:bump`. +- 7dcff85: Remove special-casing for `@types` packages when generating dependency entries + during templating +- 0aff006: Bumped the version range for `html-webpack-plugin` to fix the `htmlPluginExports.getCompilationHooks is not a function` error when using experimental Rspack. +- 583f3d4: Added `@backstage/cli/config/prettier` as a replacement for `@spotify/prettier-config`, but with the same configuration. +- 5f04976: Update `rollup` to avoid issues with build output when running `backstage-cli package build`. +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/release-manifests@0.0.12-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/types@1.2.0 + +## @backstage/cli-node@0.2.11-next.0 + +### Patch Changes + +- af665ea: add PackageManager and Lockfile interfaces for future use +- cbfc69e: Internal refactor +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/core-app-api@1.15.3-next.0 + +### Patch Changes + +- e5fa018: The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes. +- 2830689: Decrease OAuth2 token refresh grace period +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-compat-api@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-components@0.16.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + +## @backstage/create-app@0.5.23-next.0 + +### Patch Changes + +- 5819f8d: Updated Dockerfile to include `backstage.json` file +- 583f3d4: Updated the template to use `@backstage/cli/config/prettier` instead of `@spotify/prettier-config`. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/dev-utils@1.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + +## @backstage/frontend-app-api@0.10.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-defaults@0.1.4-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-defaults@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.3-next.0 + +## @backstage/frontend-plugin-api@0.9.3-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-test-utils@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/integration-react@1.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/release-manifests@0.0.12-next.0 + +### Patch Changes + +- 2e140dc: Switch to native fetch for loading release manifests + +## @techdocs/cli@1.8.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/plugin-techdocs-node@1.12.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + +## @backstage/test-utils@1.7.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/theme@0.6.3-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. + +## @backstage/plugin-api-docs@0.12.2-next.0 + +### Patch Changes + +- 11babd9: Fix link styling in ProvidedApisCard component so it aligns with other card components. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app@0.1.4-next.0 + +### Patch Changes + +- e5fa018: The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes. +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app-backend@0.4.3-next.0 + +### Patch Changes + +- 74c3f2a: Fixed a bug where config would not be injected on the `/` and `/index.html` paths. +- d66fa80: Fix root route handling when query parameters are present +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.0 + +## @backstage/plugin-app-node@0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config-loader@1.9.2 + +## @backstage/plugin-app-visualizer@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-auth-backend@0.24.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-auth-backend@0.24.1-next.0 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-auth-backend@0.24.1-next.0 + +## @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-auth-node@0.5.5-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-react@0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-catalog@1.25.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-catalog-backend@1.28.1-next.0 + +### Patch Changes + +- f159b25: Compute deltas more efficiently, which generally leads to less wasted processing cycles +- 56511ba: Be more aggressive in dequeueing entities for stitching +- 71152e3: Correctly report stitching queue length +- 3ab57c6: Support changing location keys on existing entities, in delta mutations +- 2924ffe: Compute some metrics using search table facet aggregations instead of reading the full refresh state +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-catalog-backend-module-aws@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.7.8-next.0 + +### Patch Changes + +- 468bbcc: Pass in a default schedule to the `GithubEntityProvider` if none is provided +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.6.1-next.0 + +### Patch Changes + +- cce9cae: Deprecate old-backend-system `IncrementalCatalogBuilder` +- 5aa44d2: Wire up the events together in the new backend system +- cbfc69e: Create a `dev/index.ts` entrypoint for `yarn start` +- 3ca5f70: Ensure that the scheduled worker task doesn't run at an unreasonably high frequency +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-catalog-backend-module-logs@0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## @backstage/plugin-catalog-backend-module-msgraph@0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-catalog-graph@0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog-import@0.12.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-node@1.14.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-catalog-react@1.14.3-next.0 + +### Patch Changes + +- f18c67d: Fix catalog filtering to allow searching entities by display name +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-test-utils@0.2.4-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-config-schema@0.1.63-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-devtools@0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-devtools-backend@0.4.3-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-events-backend@0.3.17-next.0 + +### Patch Changes + +- 1577511: Allow configuring a timeout for event bus polling requests. This can be set like so in your app-config: + + ```yaml + events: + notifyTimeoutMs: 30000 + ``` + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-events-backend-module-azure@0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## @backstage/plugin-events-backend-module-gerrit@0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## @backstage/plugin-events-backend-module-github@0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + +## @backstage/plugin-events-backend-test-utils@0.1.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.0 + +## @backstage/plugin-events-node@0.4.6-next.0 + +### Patch Changes + +- 79a06f6: Clarified purpose of subscriber ID in TSDoc for `EventsServiceSubscribeOptions`. + +- 1577511: Allow configuring a timeout for event bus polling requests. This can be set like so in your app-config: + + ```yaml + events: + notifyTimeoutMs: 30000 + ``` + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-home@0.8.3-next.0 + +### Patch Changes + +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-home-react@0.1.21-next.0 + +### Patch Changes + +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-kubernetes@0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.0 + +## @backstage/plugin-kubernetes-backend@0.19.1-next.0 + +### Patch Changes + +- cbfc69e: Create a `dev/index.ts` entrypoint for `yarn start` +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-node@0.2.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.0 + +## @backstage/plugin-kubernetes-node@0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-kubernetes-react@0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-notifications@0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-notifications-backend@0.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + +## @backstage/plugin-notifications-backend-module-email@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + +## @backstage/plugin-notifications-node@0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-node@0.1.15-next.0 + +## @backstage/plugin-org@0.6.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-org-react@0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-permission-backend@0.5.52-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## @backstage/plugin-permission-node@0.8.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-proxy-backend@0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder@1.27.2-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.4-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.3-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.3-next.0 + +### Patch Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-github@0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.16-next.0 + +## @backstage/plugin-scaffolder-common@1.5.8-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-scaffolder-node@0.6.1-next.0 + +### Patch Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.2.0-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-react@1.14.2-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-search@1.4.21-next.0 + +### Patch Changes + +- d311c84: Use Select from core-components and update Lifecycle filter to use Select instead checkboxes. +- Updated dependencies + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend@1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-explore@0.2.6-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-pg@0.5.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-techdocs-node@1.12.15-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-node@1.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-react@1.8.4-next.0 + +### Patch Changes + +- d311c84: Use Select from core-components and update Lifecycle filter to use Select instead checkboxes. +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-signals@0.0.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-signals-backend@0.2.4-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + +## @backstage/plugin-signals-node@0.1.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-techdocs@1.11.3-next.0 + +### Patch Changes + +- 7d8777d: Added support for the Search bar in docs residing in the entity page tab, and not only the global "/docs" page. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.43-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## @backstage/plugin-techdocs-backend@1.11.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + - @backstage/plugin-techdocs-node@1.12.15-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## @backstage/plugin-techdocs-node@1.12.15-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-react@1.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/plugin-user-settings@0.8.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.104-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-scaffolder@1.27.2-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-search@1.4.21-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/plugin-home@0.8.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-api-docs@0.12.2-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.14-next.0 + - @backstage/plugin-catalog-import@0.12.8-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.0 + - @backstage/plugin-devtools@0.1.22-next.0 + - @backstage/plugin-kubernetes@0.12.2-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.0 + - @backstage/plugin-notifications@0.4.2-next.0 + - @backstage/plugin-org@0.6.34-next.0 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-signals@0.0.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + - @backstage/plugin-user-settings@0.8.17-next.0 + +## example-app-next@0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-scaffolder@1.27.2-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-search@1.4.21-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/plugin-home@0.8.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-api-docs@0.12.2-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/frontend-defaults@0.1.4-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-app-visualizer@0.1.14-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.14-next.0 + - @backstage/plugin-catalog-import@0.12.8-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.0 + - @backstage/plugin-kubernetes@0.12.2-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.0 + - @backstage/plugin-notifications@0.4.2-next.0 + - @backstage/plugin-org@0.6.34-next.0 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-signals@0.0.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + - @backstage/plugin-user-settings@0.8.17-next.0 + +## app-next-example-plugin@0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-components@0.16.2-next.0 + +## example-backend@0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/plugin-scaffolder-backend@1.28.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.0 + - @backstage/plugin-app-backend@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-backend@0.5.52-next.0 + - @backstage/plugin-devtools-backend@0.4.3-next.0 + - @backstage/plugin-signals-backend@0.2.4-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/plugin-kubernetes-backend@0.19.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-auth-backend@0.24.1-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.0 + - @backstage/plugin-notifications-backend@0.4.4-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-proxy-backend@0.5.9-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.5.3-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.4-next.0 + - @backstage/plugin-search-backend@1.7.1-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-techdocs-backend@1.11.4-next.0 + +## example-backend-legacy@0.2.105-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-backend@1.28.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.0 + - @backstage/plugin-app-backend@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-backend@0.5.52-next.0 + - @backstage/plugin-devtools-backend@0.4.3-next.0 + - @backstage/plugin-signals-backend@0.2.4-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/plugin-kubernetes-backend@0.19.1-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-auth-backend@0.24.1-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-proxy-backend@0.5.9-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.3-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.3-next.0 + - @backstage/plugin-search-backend@1.7.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + - @backstage/plugin-techdocs-backend@1.11.4-next.0 + +## e2e-test@0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @internal/frontend@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @internal/scaffolder@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + +## techdocs-cli-embedded-app@0.2.103-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## yarn-plugin-backstage@0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/release-manifests@0.0.12-next.0 + - @backstage/cli-common@0.1.15 + +## @internal/plugin-todo-list@1.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## @internal/plugin-todo-list-backend@1.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 diff --git a/docs/releases/v1.34.0-next.1-changelog.md b/docs/releases/v1.34.0-next.1-changelog.md new file mode 100644 index 0000000000..b61e5b1560 --- /dev/null +++ b/docs/releases/v1.34.0-next.1-changelog.md @@ -0,0 +1,2146 @@ +# Release v1.34.0-next.1 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.34.0-next.1](https://backstage.github.io/upgrade-helper/?to=1.34.0-next.1) + +## @backstage/backend-app-api@1.1.0-next.1 + +### Minor Changes + +- 12eac85: **EXPERIMENTAL**: Adds a new `instanceMetadataService` to hold information about a specific backend instance. + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/backend-plugin-api@1.1.0-next.1 + +### Minor Changes + +- 12eac85: **EXPERIMENTAL**: Adds a new `instanceMetadataService` to hold information about a specific backend instance. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/catalog-client@1.9.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend@1.29.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. +- 1d0bc11: Fetch all facets in a single database query + +### Patch Changes + +- e4aab10: Fix a bug where sometimes the `by-query` endpoint could return nulls for entities that were not yet stitched. +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-catalog-node@1.15.0-next.1 + +### Minor Changes + +- 8edc4cd: Updated the `catalogServiceMock` return type to match both `CatalogService` and `CatalogApi` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-devtools-backend@0.5.0-next.1 + +### Minor Changes + +- c781a9a: **BREAKING** Removed support for what is known as the legacy backend, please use the New Backend System. + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-events-backend@0.4.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-search-backend@1.8.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/app-defaults@1.5.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/backend-defaults@0.6.0-next.1 + +### Patch Changes + +- fe87fbf: Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. +- 1ac6b72: Support `connection.type: cloudsql` in database client for usage with `@google-cloud/cloud-sql-connector` and `iam` auth +- 5c9cc05: Use native fetch instead of node-fetch +- cf627c6: Fixed an issue in the WinstonLogger where Errors thrown and given to logger.error with field values that could not be cast to a string would throw a TypeError +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/backend-dynamic-feature-service@0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/backend-openapi-utils@0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/backend-test-utils@1.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/cli@0.29.3-next.1 + +### Patch Changes + +- a49030a: Add support for `--output-file` option from ESLint to `package lint` and `repo lint` commands. +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## @backstage/config-loader@1.9.3-next.0 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/core-compat-api@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-components@0.16.2-next.1 + +### Patch Changes + +- e47be38: Added data-testid to placeholder rendered by Progress component to simplify assertions in tests +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/theme@0.6.3-next.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/create-app@0.5.23-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/dev-utils@1.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + +## @backstage/frontend-app-api@0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-defaults@0.1.4-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-defaults@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-app@0.1.4-next.1 + +## @backstage/frontend-plugin-api@0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-test-utils@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.4-next.1 + +## @backstage/release-manifests@0.0.12-next.1 + +### Patch Changes + +- b29eaea: Allow overriding the fetch function used inside getManifestByVersion + +## @backstage/repo-tools@0.12.0-next.1 + +### Patch Changes + +- 860e3b5: Generated OpenAPI clients now support paths with tags. +- 00058d0: The `generate-patch` command will now add a single resolution entry for all versions of the patched package, rather than separate entries for each version query. +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/errors@1.2.5 + +## @techdocs/cli@1.8.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/plugin-techdocs-node@1.12.15-next.1 + +## @backstage/plugin-api-docs@0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app@0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-app-backend@0.4.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.1 + +## @backstage/plugin-app-node@0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-app-visualizer@0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## @backstage/plugin-auth-backend@0.24.1-next.1 + +### Patch Changes + +- c907440: Improved error forwarding for OAuth refresh endpoints +- 40518ab: Fix issue with `jwks` endpoint returning invalid data with `firestore` +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.1 + +### Patch Changes + +- 79b055a: Pass through `includeGrantedScopes` in order to persist scopes across refresh calls +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + +## @backstage/plugin-auth-node@0.5.5-next.1 + +### Patch Changes + +- c907440: Improved error forwarding for OAuth refresh endpoints +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-react@0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog@1.25.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-azure@0.3.0-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-catalog-backend-module-github@0.7.8-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.6.1-next.1 + +### Patch Changes + +- fe87fbf: Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-catalog-backend-module-ldap@0.11.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-logs@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-catalog-backend-module-msgraph@0.6.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-catalog-graph@0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog-import@0.12.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-catalog-react@1.14.3-next.1 + +### Patch Changes + +- d97a2cd: Fixed an issue causing the `EntityOwnerPicker` to reset scrolling when more elements are loaded. +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/frontend-test-utils@0.2.4-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## @backstage/plugin-config-schema@0.1.63-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-devtools@0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-module-azure@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-module-gerrit@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-module-github@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-module-gitlab@0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-backend-test-utils@0.1.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-events-node@0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## @backstage/plugin-home@0.8.3-next.1 + +### Patch Changes + +- 7248f3b: Added a new Quick Start Card to `plugin-home`, which can display basic info to get users the info they need to onboard to the Catalog. + + import { QuickStartCard } from '@backstage/plugin-home'; + + } + cardDescription="Backstage system model will help you create new entities" + video={ + + } + downloadImage={ + + } + /> + + See the [storybook examples](https://backstage.io/storybook/?path=/story/plugins-home-components-quickstartcard--default) + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.1 + +## @backstage/plugin-home-react@0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-kubernetes@0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.1 + +## @backstage/plugin-kubernetes-backend@0.19.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-kubernetes-node@0.2.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-kubernetes-cluster@0.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.1 + +## @backstage/plugin-kubernetes-node@0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-kubernetes-react@0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## @backstage/plugin-notifications@0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-notifications-backend@0.4.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-notifications-common@0.0.6 + +## @backstage/plugin-notifications-backend-module-email@0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + +## @backstage/plugin-notifications-node@0.2.10-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-notifications-common@0.0.6 + +## @backstage/plugin-org@0.6.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-catalog-common@1.1.1 + +## @backstage/plugin-org-react@0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + +## @backstage/plugin-permission-backend@0.5.52-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-permission-node@0.8.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## @backstage/plugin-proxy-backend@0.5.9-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder@1.27.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## @backstage/plugin-scaffolder-backend@1.28.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-notifications-common@0.0.6 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-node@0.6.2-next.1 + +### Patch Changes + +- 1a23421: Make sure that isomorphic git push commands are not proxied. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-test-utils@1.2.0-next.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-react@1.14.2-next.1 + +### Patch Changes + +- c846d76: Updated dependency `flatted` to `3.3.2`. +- b21a5ae: Open links in the scaffolder entity and step descriptions in a new tab, to ensure consistency and improve user experience +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## @backstage/plugin-search@1.4.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + +## @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.1 + +### Patch Changes + +- 991c9fe: Update the ElasticSearchSearchEngine translator to handle phrase searches. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-explore@0.2.6-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-pg@0.5.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-node@1.12.15-next.1 + +## @backstage/plugin-search-backend-node@1.3.6-next.1 + +### Patch Changes + +- 5ae8a2c: Removed unnecessary dependency on `@backstage/backend-defaults`. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-search-react@1.8.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## @backstage/plugin-signals@0.0.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + +## @backstage/plugin-signals-backend@0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-signals-node@0.1.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## @backstage/plugin-techdocs@1.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.43-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## @backstage/plugin-techdocs-backend@1.11.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-node@1.12.15-next.1 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## @backstage/plugin-techdocs-node@1.12.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-react@1.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## @backstage/plugin-user-settings@0.8.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.104-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.8.3-next.1 + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-api-docs@0.12.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-catalog-graph@0.4.14-next.1 + - @backstage/plugin-catalog-import@0.12.8-next.1 + - @backstage/plugin-kubernetes@0.12.2-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.1 + - @backstage/plugin-org@0.6.34-next.1 + - @backstage/plugin-scaffolder@1.27.2-next.1 + - @backstage/plugin-search@1.4.21-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/plugin-user-settings@0.8.17-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.1 + - @backstage/plugin-devtools@0.1.22-next.1 + - @backstage/plugin-notifications@0.4.2-next.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-signals@0.0.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## example-app-next@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.8.3-next.1 + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-api-docs@0.12.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-catalog-graph@0.4.14-next.1 + - @backstage/plugin-catalog-import@0.12.8-next.1 + - @backstage/plugin-kubernetes@0.12.2-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.1 + - @backstage/plugin-org@0.6.34-next.1 + - @backstage/plugin-scaffolder@1.27.2-next.1 + - @backstage/plugin-search@1.4.21-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/plugin-user-settings@0.8.17-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-defaults@0.1.4-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-app@0.1.4-next.1 + - @backstage/plugin-app-visualizer@0.1.14-next.1 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.1 + - @backstage/plugin-notifications@0.4.2-next.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-signals@0.0.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## app-next-example-plugin@0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## example-backend@0.0.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-search-backend@1.8.0-next.1 + - @backstage/plugin-devtools-backend@0.5.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.1 + - @backstage/plugin-notifications-backend@0.4.4-next.1 + - @backstage/plugin-permission-backend@0.5.52-next.1 + - @backstage/plugin-techdocs-backend@1.11.4-next.1 + - @backstage/plugin-signals-backend@0.2.4-next.1 + - @backstage/plugin-proxy-backend@0.5.9-next.1 + - @backstage/plugin-app-backend@0.4.3-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.1 + - @backstage/plugin-kubernetes-backend@0.19.1-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-scaffolder-backend@1.28.0-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.1 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-permission-common@0.8.2 + +## example-backend-legacy@0.2.105-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.1 + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-search-backend@1.8.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.1 + - @backstage/plugin-permission-backend@0.5.52-next.1 + - @backstage/plugin-techdocs-backend@1.11.4-next.1 + - @backstage/plugin-signals-backend@0.2.4-next.1 + - @backstage/plugin-proxy-backend@0.5.9-next.1 + - @backstage/plugin-app-backend@0.4.3-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.1 + - @backstage/plugin-kubernetes-backend@0.19.1-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-scaffolder-backend@1.28.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.1 + +## e2e-test@0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## @internal/frontend@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @internal/scaffolder@0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## techdocs-cli-embedded-app@0.2.103-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## yarn-plugin-backstage@0.0.4-next.1 + +### Patch Changes + +- 48cc7c5: Use yarn's built-in http utilities for fetching release manifests +- Updated dependencies + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/cli-common@0.1.15 + +## @internal/plugin-todo-list@1.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + +## @internal/plugin-todo-list-backend@1.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 diff --git a/docs/releases/v1.34.0-next.2-changelog.md b/docs/releases/v1.34.0-next.2-changelog.md new file mode 100644 index 0000000000..7be3b11c59 --- /dev/null +++ b/docs/releases/v1.34.0-next.2-changelog.md @@ -0,0 +1,2268 @@ +# Release v1.34.0-next.2 + +Upgrade Helper: [https://backstage.github.io/upgrade-helper/?to=1.34.0-next.2](https://backstage.github.io/upgrade-helper/?to=1.34.0-next.2) + +## @backstage/backend-app-api@1.1.0-next.2 + +### Minor Changes + +- ebf083d: Service factories added by feature loaders now have lower priority and will be ignored if a factory for the same service is added directly by `backend.add(serviceFactory)`. + +### Patch Changes + +- 0e9c9fa: As soon as a backend termination signal is received, call before shutting down root lifecycle hooks. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/backend-defaults@0.6.0-next.2 + +### Minor Changes + +- fd5d337: Added a new `backend.health.headers` configuration that can be used to set additional headers to include in health check responses. + + **BREAKING CONSUMERS**: As part of this change the `createHealthRouter` function exported from `@backstage/backend-defaults/rootHttpRouter` now requires the root config service to be passed through the `config` option. + +- 3f34ea9: Throttles Bitbucket Server API calls + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 57e0b11: The user and plugin token verification in the default `AuthService` implementation will no longer forward verification errors to the caller, and instead log them as warnings. +- 57e0b11: The default `authServiceFactory` now correctly depends on the plugin scoped `Logger` services rather than the root scoped one. +- 0e9c9fa: Implements the `DefaultRootLifecycleService.addBeforeShutdownHook` method, and updates `DefaultRootHttpRouterService` and `DefaultRootHealthService` to listen to that event to stop accepting traffic and close service connections. +- d0cbd82: Remove use of the `stoppable` library on the `DefaultRootHttpRouterService` as Node's native http server [close](https://nodejs.org/api/http.html#serverclosecallback) method already drains requests. + Also, we pass a new `lifecycleMiddleware` to the `rootHttpRouterServiceFactory` configure function that must be called manually if you don't call `applyDefaults`. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + +## @backstage/backend-openapi-utils@0.4.0-next.2 + +### Minor Changes + +- afcebea: Fixed a Typescript error when trying to use the new OpenAPI server-side generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog@1.26.0-next.2 + +### Minor Changes + +- 25beb82: Adds an optional columns attribute to HasSubdomainsCardProps and changes its default columns +- 39f1abc: Consistent title behaviour across CatalogTable, CursorPaginatedCatalogTable, and OffsetPaginatedCatalogTable. + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + +## @backstage/plugin-catalog-backend@1.29.0-next.2 + +### Minor Changes + +- c1307b4: Implement `/entities` in terms of `queryEntities` to not run into memory and performance problems on large catalogs + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 8013c9c: Perform the by-query count inlined with the main query +- feba9ee: Use a join based strategy for filtering, when having small page sizes +- 1fdb48e: Use a faster count method on pg when computing some metrics +- 0c33465: Implement `/entities/by-name/:kind/:namespace/:name` using `getEntitiesByRefs` +- d93390d: When parsing filters, do not make redundant `anyOf` and `allOf` nodes when there's only a single entry within them +- 24ecea8: Avoid extra ordering in by-query when the user doesn't ask for it +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-server@0.3.0-next.2 + +### Minor Changes + +- 3f34ea9: Throttles Bitbucket Server API calls + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-catalog-backend-module-gitlab@0.6.0-next.2 + +### Minor Changes + +- 99dce5c: Implemented discovery for top-level groups defined in config.group or if undefined global top-level group in Gitlab + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-notifications@0.5.0-next.2 + +### Minor Changes + +- fc15b77: Switched to using the new `/notifications` endpoints. Be sure to update the `notifications` plugin backend before deploying this frontend plugin change. + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + - @backstage/plugin-signals-react@0.0.8-next.0 + +## @backstage/plugin-notifications-backend@0.5.0-next.2 + +### Minor Changes + +- fc15b77: **BREAKING**: Removed redundant `/health` endpoint, switch to using [the built-in endpoint instead](https://backstage.io/docs/backend-system/core-services/root-health). + +### Patch Changes + +- fc15b77: Deprecated root '/' endpoints, moving them under `/notifications` instead. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## @backstage/app-defaults@1.5.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/backend-dynamic-feature-service@0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-app-node@0.1.28-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/backend-plugin-api@1.1.0-next.2 + +### Patch Changes + +- 0e9c9fa: The `RootLifecycleService` now has a new `addBeforeShutdownHook` method, and hooks added through this method will run immediately when a termination event is received. + + The backend will not proceed with the shutdown and run the `Shutdown` hooks until all `BeforeShutdown` hooks have completed. + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/backend-test-utils@1.2.0-next.2 + +### Patch Changes + +- 0e9c9fa: Mock the new `RootLifecycleService.addBeforeShutdownHook` method. +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/catalog-client@1.9.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + +## @backstage/catalog-model@1.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## @backstage/cli@0.29.3-next.2 + +### Patch Changes + +- 62a9062: Updated dependency `@module-federation/enhanced` to `^0.8.0`. +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.16.0-next.1 + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/types@1.2.0 + +## @backstage/cli-node@0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/types@1.2.0 + +## @backstage/config@1.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## @backstage/config-loader@1.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/core-app-api@1.15.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-compat-api@0.3.4-next.2 + +### Patch Changes + +- 1f30730: Updated dependency `@oriflame/backstage-plugin-score-card` to `^0.9.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-components@0.16.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/core-plugin-api@1.10.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/create-app@0.5.23-next.2 + +### Patch Changes + +- e913fdf: Add github backend module to create-app and improve error messages +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## @backstage/dev-utils@1.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + +## @backstage/errors@1.2.6-next.0 + +### Patch Changes + +- 1d4b5b9: Trim `error.cause.stack` in addition to `error.stack` when trimming stack traces from serialized errors. +- Updated dependencies + - @backstage/types@1.2.0 + +## @backstage/frontend-app-api@0.10.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-defaults@0.1.4-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-defaults@0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-app@0.1.4-next.2 + +## @backstage/frontend-plugin-api@0.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/frontend-test-utils@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/test-utils@1.7.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.4-next.2 + +## @backstage/integration@1.16.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + +## @backstage/integration-aws-node@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + +## @backstage/integration-react@1.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/repo-tools@0.12.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + +## @techdocs/cli@1.8.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-techdocs-node@1.12.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + +## @backstage/test-utils@1.7.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/plugin-api-docs@0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/plugin-app@0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/plugin-app-backend@0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-app-node@0.1.28-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-app-node@0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/config-loader@1.9.3-next.1 + +## @backstage/plugin-app-visualizer@0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## @backstage/plugin-auth-backend@0.24.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.2 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @backstage/plugin-auth-backend-module-pinniped-provider@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-auth-backend-module-vmware-cloud-provider@0.4.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## @backstage/plugin-auth-node@0.5.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-auth-react@0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-catalog-backend-module-aws@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## @backstage/plugin-catalog-backend-module-azure@0.3.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-catalog-backend-module-bitbucket-cloud@0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-gcp@0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## @backstage/plugin-catalog-backend-module-gerrit@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-catalog-backend-module-github@0.7.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-github-org@0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-catalog-backend-module-gitlab-org@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.6.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-catalog-backend-module-incremental-ingestion@0.6.1-next.2 + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- d42ecb0: Remove backend-common package from incremental-ingestion plugin and update related code +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-catalog-backend-module-ldap@0.11.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-logs@0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-catalog-backend-module-msgraph@0.6.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-backend-module-puppetdb@0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.6-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-catalog-common@1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-catalog-graph@0.4.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + +## @backstage/plugin-catalog-import@0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-catalog-node@1.15.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-catalog-react@1.14.3-next.2 + +### Patch Changes + +- 95092a6: Fixed an issue where `` would re-render its children on page load for smaller screens, potentially leading to unnecessary additional backend requests. +- 4a43398: Fixed an issue where the `EntityOwnerPicker` component failed to load when the `mode` prop was set to `owners-only`. In this mode, the `EntityOwnerPicker` does not load details about the owners, such as `displayName` or `title`. To display these details, use `mode=all` instead. +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/frontend-test-utils@0.2.4-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## @backstage/plugin-catalog-unprocessed-entities-common@0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-config-schema@0.1.63-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-devtools@0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-devtools-common@0.1.14-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## @backstage/plugin-devtools-backend@0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.14-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-devtools-common@0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-events-backend@0.4.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-events-backend-module-aws-sqs@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-events-backend-module-azure@0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-events-backend-module-bitbucket-cloud@0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-events-backend-module-gerrit@0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-events-backend-module-github@0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-events-backend-module-gitlab@0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-events-backend-test-utils@0.1.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.2 + +## @backstage/plugin-events-node@0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-home@0.8.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.2 + +## @backstage/plugin-home-react@0.1.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## @backstage/plugin-kubernetes@0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.2 + +## @backstage/plugin-kubernetes-backend@0.19.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-kubernetes-node@0.2.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-kubernetes-cluster@0.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.2 + +## @backstage/plugin-kubernetes-common@0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-kubernetes-node@0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## @backstage/plugin-kubernetes-react@0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## @backstage/plugin-notifications-backend-module-email@0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## @backstage/plugin-notifications-common@0.0.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-notifications-node@0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## @backstage/plugin-org@0.6.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## @backstage/plugin-org-react@0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## @backstage/plugin-permission-backend@0.5.52-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-permission-common@0.8.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-permission-node@0.8.6-next.2 + +### Patch Changes + +- b149e2a: The `createPermissionIntegrationRouter` function now detects and prevents the exposure of duplicate permissions. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-permission-react@0.4.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-proxy-backend@0.5.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder@1.27.2-next.2 + +### Patch Changes + +- 184161f: Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder. +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## @backstage/plugin-scaffolder-backend@1.28.0-next.2 + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 6c326cf: The --no-node-snapshot check needs to be done against process.execArgv instead of process.argv +- e913fdf: Add github backend module to create-app and improve error messages +- 0851834: Resolved an issue where the `templateManagementPermission` was not being exposed through the `/permissions/metadata` endpoint. +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + +## @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-cookiecutter@0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-gcp@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.2 + +### Patch Changes + +- e913fdf: Add github backend module to create-app and improve error messages +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-backend-module-sentry@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + +## @backstage/plugin-scaffolder-backend-module-yeoman@0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.2 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-common@1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-scaffolder-node@0.6.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.2.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/types@1.2.0 + +## @backstage/plugin-scaffolder-react@1.14.2-next.2 + +### Patch Changes + +- 184161f: Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## @backstage/plugin-search@1.4.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + +## @backstage/plugin-search-backend@1.8.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-explore@0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-pg@0.5.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-stack-overflow-collator@0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-techdocs-node@1.12.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-backend-node@1.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-search-common@1.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## @backstage/plugin-search-react@1.8.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.16-next.0 + +## @backstage/plugin-signals@0.0.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.8-next.0 + +## @backstage/plugin-signals-backend@0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-signals-node@0.1.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-signals-react@0.0.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + +## @backstage/plugin-techdocs@1.11.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## @backstage/plugin-techdocs-addons-test-utils@1.0.43-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/test-utils@1.7.3-next.1 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## @backstage/plugin-techdocs-backend@1.11.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + - @backstage/plugin-techdocs-node@1.12.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## @backstage/plugin-techdocs-node@1.12.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-techdocs-common@0.1.0 + +## @backstage/plugin-techdocs-react@1.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/version-bridge@1.0.10 + +## @backstage/plugin-user-settings@0.8.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.8-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## @backstage/plugin-user-settings-backend@0.2.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## example-app@0.2.104-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/plugin-notifications@0.5.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/plugin-scaffolder@1.27.2-next.2 + - @backstage/plugin-api-docs@0.12.2-next.2 + - @backstage/plugin-catalog-graph@0.4.14-next.2 + - @backstage/plugin-catalog-import@0.12.8-next.2 + - @backstage/plugin-org@0.6.34-next.2 + - @backstage/plugin-user-settings@0.8.17-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.2 + - @backstage/plugin-devtools@0.1.22-next.2 + - @backstage/plugin-home@0.8.3-next.2 + - @backstage/plugin-kubernetes@0.12.2-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.2 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-search@1.4.21-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-signals@0.0.14-next.2 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## example-app-next@0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/plugin-notifications@0.5.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/plugin-scaffolder@1.27.2-next.2 + - @backstage/plugin-api-docs@0.12.2-next.2 + - @backstage/plugin-catalog-graph@0.4.14-next.2 + - @backstage/plugin-catalog-import@0.12.8-next.2 + - @backstage/plugin-org@0.6.34-next.2 + - @backstage/plugin-user-settings@0.8.17-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-defaults@0.1.4-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-app@0.1.4-next.2 + - @backstage/plugin-app-visualizer@0.1.14-next.2 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.2 + - @backstage/plugin-home@0.8.3-next.2 + - @backstage/plugin-kubernetes@0.12.2-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.2 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-search@1.4.21-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-signals@0.0.14-next.2 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## app-next-example-plugin@0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## example-backend@0.0.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.28.0-next.2 + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.2 + - @backstage/plugin-notifications-backend@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-app-backend@0.4.3-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.2 + - @backstage/plugin-devtools-backend@0.5.0-next.2 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-kubernetes-backend@0.19.1-next.2 + - @backstage/plugin-proxy-backend@0.5.9-next.2 + - @backstage/plugin-search-backend@1.8.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-signals-backend@0.2.4-next.2 + - @backstage/plugin-techdocs-backend@1.11.4-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.2 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.2 + - @backstage/plugin-permission-backend@0.5.52-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.2 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## example-backend-legacy@0.2.105-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.28.0-next.2 + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-app-backend@0.4.3-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-kubernetes-backend@0.19.1-next.2 + - @backstage/plugin-proxy-backend@0.5.9-next.2 + - @backstage/plugin-search-backend@1.8.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-signals-backend@0.2.4-next.2 + - @backstage/plugin-techdocs-backend@1.11.4-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-permission-backend@0.5.52-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.2 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## e2e-test@0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + +## @internal/frontend@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## @internal/scaffolder@0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## techdocs-cli-embedded-app@0.2.103-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/test-utils@1.7.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## @internal/plugin-todo-list@1.0.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## @internal/plugin-todo-list-backend@1.0.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## @internal/plugin-todo-list-common@1.0.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.3-next.0 diff --git a/docs/tooling/local-dev/linking-local-packages.md b/docs/tooling/local-dev/linking-local-packages.md index 853f470a39..9205195f64 100644 --- a/docs/tooling/local-dev/linking-local-packages.md +++ b/docs/tooling/local-dev/linking-local-packages.md @@ -57,7 +57,7 @@ After making local changes to a package in an external workspace you might often For example, if you've made changes to the `@backstage/backend-app-api` package in a local clone of the main `backstage` repository, you can generate a patch for your internal project as follows: ```bash title="Run in the cloned backstage repository" -yarn backstage-repo-tools generate patch @backstage/backend-app-api --target ../our-developer-portal +yarn backstage-repo-tools generate-patch @backstage/backend-app-api --target ../our-developer-portal ``` This will generate a patch file in your `our-developer-portal` workspace. The patch will be based on the most recently released version of the source package, with the additional changes on top. diff --git a/docs/tutorials/migrate-to-mui5.md b/docs/tutorials/migrate-to-mui5.md index c65abbc680..a0f8a9017e 100644 --- a/docs/tutorials/migrate-to-mui5.md +++ b/docs/tutorials/migrate-to-mui5.md @@ -4,6 +4,12 @@ title: Migrating from Material UI v4 to v5 description: Additional resources for the Material UI v5 migration guide specifically for Backstage --- +:::info + +We are in the process of determining the path forward regarding a New Design System for Backstage, for the time being we recommend pausing any migrations to MUI v5 until this has been settled. More details can be found in ["RFC: New design system for Backstage"](https://github.com/backstage/backstage/issues/27726). + +::: + Backstage supports developing new plugins or components using Material UI v5. At the same time, large parts of the application as well as existing plugins will still be using Material UI v4. To support Material UI v4 and v5 at the same time, we have introduced a new concept called the `UnifiedTheme`. The goal of the `UnifiedTheme` is to allow gradual migration by running both versions in parallel, applying theme options similarly & supporting potential future versions of Material UI. By default, the `UnifiedThemeProvider` is already used. If you add a custom theme in your `createApp` function, you would need to replace the Material UI `ThemeProvider` with the `UnifiedThemeProvider`: diff --git a/microsite/blog/2023-05-06-backstage-deploy-alpha.mdx b/microsite/blog/2023-05-06-backstage-deploy-alpha.mdx index 1a783b026a..126bbb9e7d 100644 --- a/microsite/blog/2023-05-06-backstage-deploy-alpha.mdx +++ b/microsite/blog/2023-05-06-backstage-deploy-alpha.mdx @@ -40,7 +40,7 @@ Deploy CLI makes use of [Pulumi](https://www.pulumi.com/docs/) which is an infra You can find the step-by-step installation documentation for Pulumi under the [Deployment section](https://backstage.io/docs/deployment/backstage-deploy/aws-lightsail). -But we summarize the steps to deploy your POC here. You can invoke the the CLI you can use the following command: +But we summarize the steps to deploy your POC here. You can invoke the CLI you can use the following command: ```bash $ npx backstage-deploy aws --create-dockerfile diff --git a/microsite/blog/2024-12-09-kubecon-slc-24.mdx b/microsite/blog/2024-12-09-kubecon-slc-24.mdx new file mode 100644 index 0000000000..c3fa2f70a8 --- /dev/null +++ b/microsite/blog/2024-12-09-kubecon-slc-24.mdx @@ -0,0 +1,201 @@ +--- +# prettier-ignore +title: "Backstage in Salt Lake City: Highlights from BackstageCon and KubeCon + CloudNativeCon North America 2024" +author: André Wanlin, Spotify & Camila Loiola, Spotify +--- + +![Beaver in front of snowcapped mountains peeking over a banner that reads BackstageCon and KubeCon + CloudNativeCon North America 2024, Salt Lake City](assets/2024-12-09/backstagecon-kubecon-2024-salt-lake-city.png) + +**tl;dr:** Salt Lake City did not disappoint! Backstage continues to be at the forefront of many conversations being had at BackstageCon and across KubeCon + CloudNativeCon. If you weren't able to join us, all the [BackstageCon talks][yt] are available for replay on YouTube. Read on for the highlights — plus, photos of super cute pups — as a treat! 🐕 + +[yt]: https://www.youtube.com/playlist?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +{/* truncate */} + +## What everyone was talking about at BackstageCon🦫 + +![Speakers on stage at BackstageCon North America 2024](assets/2024-12-09/kc24slc-spotify-backstagecon.jpg) + +[BackstageCon](https://events.linuxfoundation.org/kubecon-cloudnativecon-north-america/co-located-events/backstagecon/) featured a day of talks tailored to the diverse Backstage community. Whether you were an evaluator, adopter, integrator, builder, or an innovator, there was something valuable for everyone. Here were the big themes from the day. + +### Evaluating Backstage ROI + +- Olivier (Avalia Systems) presented what makes digital portals [helpful to C-level executives][olivier]. + +- Himanshu (Harness) shared strategies for adopting Backstage in ways that drive [meaningful value for engineers][himanshu]. + +- Eric (Quantum Metric) explained [how startups can benefit][eric] from what big techies have been contributing to Backstage. + +- Tom (Spotify) shared how developer productivity furthers Spotify’s mission to [empower creators][tom] and what the future holds for Backstage. + +[olivier]: https://youtu.be/kb3F98fKvaQ?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[himanshu]: https://youtu.be/FACtDHQvNf0?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[eric]: https://youtu.be/9qPsuMSw_dM?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[tom]: https://youtu.be/AU9BwkRMmMY?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +### Sharing Backstage adoption journeys + +- A panel discussion — featuring practitioners from Adobe, American Airlines, JPMorgan Chase, Red Hat, and Roku — showcased [real-world adoption stories from large companies][panel], spanning various stages of Backstage usage. Hear how devs at American Airlines can use Scaffolder to get a new site provisioned and deployed on the .aa.com domain in 20 minutes. “I’ve done it in seven,” said Jay Cox, principal engineer. “It used to take a month.” + +- Lizzie (Booz Allen Hamilton) explored corporate barriers to Backstage adoption and lessons learned along the way, including how to navigate [cultural tensions][lizzie] and the importance of listening to your devs, in order to bring the latest advancements in developer experience to a government consulting company that’s going on “110 years young”. + +- Amber and Daniel (Liatrio) elaborated on why [automated governance][amber] belongs inside Backstage portals to facilitate centralized compliance — so your devs don't get held up from going to prod by unforeseen checks. + +[panel]: https://youtu.be/DAjhjS2Xg4Q?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[lizzie]: https://youtu.be/RTYVmMbkdNA?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[amber]: https://youtu.be/GaGbjMJCcRU?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +### Maintaining a Backstage instance + +- Djamaile and Mitch (Spotify) provided [actionable tips][djamaile] for managing Backstage instances, including how to keep them aligned with the latest open source features. + +- Ashna and Mesut (Booking.com) showed how to customize your instance to mirror your company's unique identity and how to leverage reusability for a [smoother user experience for your devs][ashna]. + +- Paul (Red Hat) presented a [platform engineer’s POV][paul] of what it means to maintain a Backstage instance. + +- Yishai (Linear B) spoke about how to approach software engineering intelligence (SEI) and developer productivity metrics inside Backstage, including [do’s and don’ts][yishai]. + +[djamaile]: https://youtu.be/dbLqwEVl52U?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[ashna]: https://youtu.be/QV40Yz2i3jQ?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[paul]: https://youtu.be/CtbfN--mJkE?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[yishai]: https://youtu.be/mxVW2AGoI3A?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +### Building with Backstage core features + +- Avantika and Emma (Spotify) walked us through the advantages of the new backend system, recommending [best practices for plugin development][tika] and showcasing why migrating to this updated version is an extensibility game changer. + +- Will and Ryan (Microsoft) shared how Software Catalog and Templates provide the model to [build visualizations][will] of your cloud native applications. + +[tika]: https://youtu.be/n7GUlLHN2tQ?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[will]: https://youtu.be/U2-Lo-yuvdc?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +### AI-powered Backstage plugins and modules + +Innovative use cases featuring AI integration took center stage. + +- Niall (Amazon Web Services) demonstrated how to [interact with plugin services][niall] using artificial intelligence prompts. + +- Ben (Red Hat) outlined [broader AI integrations][ben] to enhance Backstage, sparking exciting possibilities for the future. + +The sessions offered a wealth of knowledge and inspiration, underscoring the versatility and potential of Backstage for organizations at every level. The Backstage booth was hopping all day long as community members and cloud natives took advantage of being able to ask the experts questions and learn more about the project. + +[niall]: https://youtu.be/DCXzCrIDOAs?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X +[ben]: https://youtu.be/cl6E0A5R_nI?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +## Backstage at the big show: KubeCon⎈ + CloudNativeCon☁️ + +![A view of the crowd entering KubeCon as seen from the top of the convention center escalator](assets/2024-12-09/kc24slc-cncf-entrance.jpg) +📸 _[See more KubeCon photos from the CNCF’s Flickr album](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/) →_ + +My friends, what an intense conference! + +Over the course of three packed days, there were a bunch of activities, including talks, a kiosk, and a Contribfest, all centered around Backstage. + +### Maintainers take the stage + +![Backstage maintainers presenting in a ballroom](assets/2024-12-09/kc24slc-spotify-maintainers.jpg) + +This may be old hat for those who are regular KubeCon attendees, but it’s still pretty exciting to catch up on all the Backstage updates straight from the core maintainers. Spotify’s Ben Lambert and Patrik Oldsberg were in the spotlight in Ballroom C addressing an attentive crowd of Backstage adopters, users, and fans. + +Highlights of their maintainers talk include: + +- **Project updates:** Yarn 4 is now the default, the new built-in event bus has arrived, and the (New) Backend System is now 1.0! +- **Security Audit:** Another security audit has been completed with the helpful support of the CNCF +- **Scaffolder updates:** Addition of Form Decorators and support for Retries! +- **New Frontend System:** Focus on the plugin builder experience! + +Watch their entire talk — “[How to Expand Your IDP: The New Building Blocks of Backstage](https://youtu.be/BzPCJMQH8tg?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X)” — for all the details. + +### Toyota and Akamai in the house + +![A packed ballroom with Backstage displayed on two large screens](assets/2024-12-09/kc24slc-cncf-toyota.jpg) +📸 [CNCF](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/) + +There were great talks from Backstage adopters during KubeCon, too. Toyota and Akamai packed the rooms with their Backstage knowledge. + +- “[Shifting Gears: Leveraging CNCF Tools to Streamline Operations at Toyota Connected][toyota]”: Benson and Rob talk about failures and successes adopting CNCF tools (including ArgoCD and Backstage) to unify operations, streamline workflows, and enhance cross-team collaboration. + +- “[From Chaos to Calm: Building a Unified and Scalable CI/CD Pipeline at Akamai][akamai]”: Tomer dives into development efficiency and how you can “conquer cloud-native deployments by adding the right tools, such as Argo Rollouts and Backstage”. + +[toyota]: https://youtu.be/4w_AC81_GZM?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X&t=856 +[akamai]: https://youtu.be/RFVB9CEEn1I?list=PL8iP9yIjU0Q3UUDXdAoCaTC4Ci8asWg-X + +### And the award goes to… + +![Adobe accepts the CNCF Top End User Award on the Keynote stage at KubeCon + CloudNativeCon North America 2024](assets/2024-12-09/kc24slc-cncf-adobe.jpg) + +📸 [CNCF](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/) + +Adobe gave a shoutout to Backstage from the Keynote mainstage on Thursday morning when they (spoiler alert) [accepted the CNCF’s Top End User Award][keynote], thanking the cloud native community and all the projects that they use. + +But Adobe isn’t just a Backstage adopter, they are a model citizen — giving back to the community through their example, having “developed a reference architecture for its IDP, built using Argo, Backstage, Helm, and Kubernetes, which other organizations can use as a template for designing and implementing their systems”. + +As Taylor Dolezal, head of ecosystem at the CNCF, [says][announcement]: “Their commitment to nurturing technological excellence and developer experience exemplifies what we hope to see in the end user ecosystem. It’s not just about tool adoption or code contributions — it’s about synthesizing these learnings into assets that empower others in their cloud native journeys.” + +Way to go, Adobe! + +[keynote]: https://youtu.be/p7J0lAU3AWo +[announcement]: https://www.cncf.io/announcements/2024/11/14/cncf-presents-top-end-user-award-to-adobe/ + +### A bustling CNCF project pavilion + +![A volunteer wearing an “Ask me about Backstage” T-shirt talks to a visitor at the project kiosk](assets/2024-12-09/kc24slc-cncf-kiosk.jpg) + +📸 [CNCF](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/) + +The CNCF Projects Pavilion was buzzing with activity all week, and the Backstage kiosk was a hub of excitement. Attendees stopped by with a mix of curiosity and enthusiasm, sparking conversations that highlighted the dynamic nature of our community. + +Curious visitors asked, “What is Backstage all about?”, while adopters sought personalized advice on customizing Backstage for their specific company needs. Contributors dropped in to say, “Hey, you reviewed my pull request!” And professionals proudly shared their achievements as Backstage experts — in fact, now there’s a way to make that expertise official — by becoming a [Certified Backstage Associate (CBA)](https://training.linuxfoundation.org/blog/just-launched-certified-backstage-associate-cba/), a new certification that was just launched by the CNCF and The Linux Foundation. + +Developers eager to give back to the community came to learn how to start contributing, and some of the kindest Backstage fans simply stopped by to say, “Thank you”. Their gratitude and encouragement are a powerful reminder of why we do what we do. + +Every interaction in person made the day special, and we wrapped up with a deep sense of fulfillment and pride in how far Backstage has come. Here's to building an even brighter future together! + +## Contribfest! It’s All About Community👩‍💻 + +![Various developers and their laptops participating in the Backstage Contribfest](assets/2024-12-09/kc24slc-spotify-cncf-contribfest.gif) + +📸 Spotify, [CNCF](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/) + +On Thursday, the first-ever Backstage Contribfest session took place — hosted by Yi Cai and Paul Schultz from Red Hat, and André Wanlin, Patrik Oldsberg, and Ben Lambert from Spotify. + +Participants who hadn't yet used or contributed to Backstage eagerly joined the project's contributors community and were eager to help. Together with the group, experienced Backstage engineers stepped in to assist attendees — whether troubleshooting environment setup or explaining how specific framework and plugin features are implemented. It was a great example of a community coming together to support learning and contribution. + +The energy in the room, with 60 enthusiastic participants, was absolutely electric! It was amazing to see ideas bouncing around, impromptu collaboration happening at every corner, and a shared passion for advancing the Backstage project. + +Among the great contributions to come out of this event are: + +- [Add Pagination to Tech Docs Table](https://github.com/backstage/backstage/pull/27694) +- [Add Home Page Quick Start Card](https://github.com/backstage/backstage/pull/27705) +- [Truncate commit message to first newline](https://github.com/backstage/community-plugins/pull/2012) + +A heartfelt thank you to everyone who joined us — it’s your talent and collaborative spirit that truly define the Backstage community. This event was a powerful reminder that it’s the people behind the project who make Backstage what it is today 💚. + +And if you missed out on the fun, it's never too late to join the Backstage community. Just follow along with the [Contribfest slide deck](https://static.sched.com/hosted_files/kccncna2024/53/KubeCon-ContribFest-Backstage-NA-2024.pdf) to get started with contributing! + +## Bonus pups!🐕 + +Nothing improves developer experience like hanging out with some fluffy friends. So please enjoy these photos from KubeCon’s “[Pet A Pup](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/with/54155382123)” station. + +(All 📸 [CNCF](https://www.flickr.com/photos/143247548@N03/albums/72177720321905538/with/54155382123). Please note: the last pup is not a pup.) + +![A labrador retriever pup in the middle of three people calmly getting pets](assets/2024-12-09/kc24slc-cncf-bestpup1.jpg) +The best labrador-retriever pup graciously accepting pets from the cloud native community. + +![A fluffy white pup staring at the camera surrounded by attendees](assets/2024-12-09/kc24slc-cncf-bestpup2.jpg) +The best fluffy white pup surrounded by admirers. + +![A lanky racing pup getting pet on the face](assets/2024-12-09/kc24slc-cncf-bestpup3.jpg) +The best racing-style pup getting face scritches. + +![A yellow pup squinting while getting pets from an attendee in a yellow shirt](assets/2024-12-09/kc24slc-cncf-bestpup4.jpg) +The best yellow pup getting pets from his twinsie. + +![A fluffy cat getting pets.](assets/2024-12-09/kc24slc-cncf-bestpup5.jpg) +See? Not a pup. But did get pets. + +[You, too, can give these pups some love](https://www.therapyanimalsutah.org). + +## Cheerio! We’ll see you in London!💂 + +And that’s a wrap on Salt Lake City! [Join us in London](https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/) in April for more community-building fun at BackstageCon and KubeCon + CloudNativeCon Europe 2025! diff --git a/microsite/blog/assets/2024-12-09/backstagecon-kubecon-2024-salt-lake-city.png b/microsite/blog/assets/2024-12-09/backstagecon-kubecon-2024-salt-lake-city.png new file mode 100644 index 0000000000..518d71fc36 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/backstagecon-kubecon-2024-salt-lake-city.png differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-adobe.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-adobe.jpg new file mode 100644 index 0000000000..c428da1c1b Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-adobe.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup1.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup1.jpg new file mode 100644 index 0000000000..919a16108d Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup1.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup2.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup2.jpg new file mode 100644 index 0000000000..b169eaa52c Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup2.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup3.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup3.jpg new file mode 100644 index 0000000000..a46e320a97 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup3.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup4.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup4.jpg new file mode 100644 index 0000000000..7fa4a405e0 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup4.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup5.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup5.jpg new file mode 100644 index 0000000000..8847adb161 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-bestpup5.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-entrance.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-entrance.jpg new file mode 100644 index 0000000000..5ec34ddf60 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-entrance.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-kiosk.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-kiosk.jpg new file mode 100644 index 0000000000..a25c55a6b3 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-kiosk.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-cncf-toyota.jpg b/microsite/blog/assets/2024-12-09/kc24slc-cncf-toyota.jpg new file mode 100644 index 0000000000..2727992735 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-cncf-toyota.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-spotify-backstagecon.jpg b/microsite/blog/assets/2024-12-09/kc24slc-spotify-backstagecon.jpg new file mode 100644 index 0000000000..579e12cad9 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-spotify-backstagecon.jpg differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-spotify-cncf-contribfest.gif b/microsite/blog/assets/2024-12-09/kc24slc-spotify-cncf-contribfest.gif new file mode 100644 index 0000000000..1a89c6586c Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-spotify-cncf-contribfest.gif differ diff --git a/microsite/blog/assets/2024-12-09/kc24slc-spotify-maintainers.jpg b/microsite/blog/assets/2024-12-09/kc24slc-spotify-maintainers.jpg new file mode 100644 index 0000000000..8a657886b0 Binary files /dev/null and b/microsite/blog/assets/2024-12-09/kc24slc-spotify-maintainers.jpg differ diff --git a/microsite/data/plugins/mend.yaml b/microsite/data/plugins/mend.yaml new file mode 100644 index 0000000000..8c18c6b71f --- /dev/null +++ b/microsite/data/plugins/mend.yaml @@ -0,0 +1,12 @@ +--- +title: Mend.io +author: Mend.io +authorUrl: https://www.mend.io/ +category: Security +description: Proactive application risk management for developer and security teams directly in Backstage +documentation: https://github.com/backstage/community-plugins/tree/main/workspaces/mend/plugins/mend +iconUrl: https://avatars.githubusercontent.com/u/105765982?s=200&v=4 +npmPackageName: '@backstage-community/plugin-mend' +tags: + - security +addedDate: '2024-10-15' diff --git a/microsite/data/plugins/npm.yaml b/microsite/data/plugins/npm.yaml new file mode 100644 index 0000000000..67f3de976f --- /dev/null +++ b/microsite/data/plugins/npm.yaml @@ -0,0 +1,9 @@ +--- +title: NPM +author: Christoph Jerolimov +authorUrl: https://github.com/christoph-jerolimov +category: Artifacts +description: A plugin that shows meta info and latest versions from a npm registry. +documentation: https://github.com/backstage/community-plugins/blob/main/workspaces/npm/plugins/npm/README.md +npmPackageName: '@backstage-community/plugin-npm' +addedDate: '2024-11-29' diff --git a/microsite/data/plugins/synergy.yaml b/microsite/data/plugins/synergy.yaml new file mode 100644 index 0000000000..6c5e722322 --- /dev/null +++ b/microsite/data/plugins/synergy.yaml @@ -0,0 +1,10 @@ +--- +title: Synergy +author: Jitesh Yadav +authorUrl: https://github.com/jiteshy +category: Collaboration +description: An inner-source dashboard for managing in-house open-source projects, issues, and attracting maintainers to foster collaboration." +documentation: https://github.com/jiteshy/backstage-plugin-synergy/blob/main/README.md +iconUrl: /img/synergy-logo.png +npmPackageName: '@jiteshy/backstage-plugin-synergy' +addedDate: '2024-12-03' diff --git a/microsite/docusaurus.config.ts b/microsite/docusaurus.config.ts index 7795e9f8a5..43bde19e35 100644 --- a/microsite/docusaurus.config.ts +++ b/microsite/docusaurus.config.ts @@ -444,8 +444,5 @@ const config: Config = { ], }, } satisfies Preset.ThemeConfig, - future: { - experimental_faster: true, - }, }; export default config; diff --git a/microsite/package.json b/microsite/package.json index ee5652416a..e3b0388903 100644 --- a/microsite/package.json +++ b/microsite/package.json @@ -17,12 +17,12 @@ "version": "docusaurus-version", "write-translations": "docusaurus-write-translations" }, - "prettier": "@spotify/prettier-config", + "prettier": "@backstage/cli/config/prettier", "dependencies": { - "@docusaurus/core": "^3.6.0", - "@docusaurus/plugin-client-redirects": "^3.6.0", - "@docusaurus/preset-classic": "^3.6.0", - "@docusaurus/types": "^3.6.0", + "@docusaurus/core": "^3.1.1", + "@docusaurus/plugin-client-redirects": "^3.1.1", + "@docusaurus/preset-classic": "^3.1.1", + "@docusaurus/types": "^3.1.1", "@mdx-js/react": "^3.0.0", "@swc/core": "^1.3.46", "clsx": "^2.0.0", @@ -36,10 +36,8 @@ "swc-loader": "^0.2.3" }, "devDependencies": { - "@docusaurus/faster": "^3.6.0", - "@docusaurus/module-type-aliases": "^3.6.0", - "@docusaurus/tsconfig": "^3.6.0", - "@spotify/prettier-config": "^15.0.0", + "@docusaurus/module-type-aliases": "^3.1.1", + "@docusaurus/tsconfig": "^3.1.1", "@types/luxon": "^3.0.0", "@types/webpack-env": "^1.18.0", "js-yaml": "^4.1.0", diff --git a/microsite/sidebars.js b/microsite/sidebars.js index 871cec0a0f..6074de0d0b 100644 --- a/microsite/sidebars.js +++ b/microsite/sidebars.js @@ -27,6 +27,16 @@ module.exports = { 'getting-started/homepage', ], }, + { + type: 'category', + label: 'Deploying Backstage', + items: [ + 'deployment/index', + 'deployment/scaling', + 'deployment/docker', + 'deployment/k8s', + ], + }, { type: 'category', label: 'Using Backstage', @@ -37,9 +47,99 @@ module.exports = { ], }, 'getting-started/keeping-backstage-updated', - 'getting-started/concepts', ], 'Core Features': [ + { + type: 'category', + label: 'Auth and Identity', + items: [ + 'auth/index', + { + type: 'category', + label: 'Included providers', + items: [ + 'auth/auth0/provider', + 'auth/atlassian/provider', + 'auth/aws-alb/provider', + 'auth/microsoft/provider', + 'auth/microsoft/easy-auth', + 'auth/bitbucket/provider', + 'auth/bitbucketServer/provider', + 'auth/cloudflare/provider', + 'auth/github/provider', + 'auth/gitlab/provider', + 'auth/google/provider', + 'auth/google/gcp-iap-auth', + 'auth/guest/provider', + 'auth/okta/provider', + 'auth/oauth2-proxy/provider', + 'auth/onelogin/provider', + 'auth/vmware-cloud/provider', + ], + }, + 'auth/identity-resolver', + 'auth/oauth', + 'auth/oidc', + 'auth/add-auth-provider', + 'auth/service-to-service-auth', + 'auth/autologout', + 'auth/troubleshooting', + ], + }, + { + type: 'category', + label: 'Kubernetes', + items: [ + 'features/kubernetes/overview', + 'features/kubernetes/installation', + 'features/kubernetes/configuration', + 'features/kubernetes/authentication', + 'features/kubernetes/authentication-strategies', + 'features/kubernetes/troubleshooting', + 'features/kubernetes/proxy', + ], + }, + { + type: 'category', + label: 'Notifications', + items: ['notifications/index'], + }, + { + type: 'category', + label: 'Permissions', + items: [ + 'permissions/overview', + 'permissions/concepts', + 'permissions/getting-started', + 'permissions/writing-a-policy', + 'permissions/frontend-integration', + 'permissions/custom-rules', + { + type: 'category', + label: 'Tutorial: using Permissions in your plugin', + items: [ + 'permissions/plugin-authors/01-setup', + 'permissions/plugin-authors/02-adding-a-basic-permission-check', + 'permissions/plugin-authors/03-adding-a-resource-permission-check', + 'permissions/plugin-authors/04-authorizing-access-to-paginated-data', + 'permissions/plugin-authors/05-frontend-authorization', + ], + }, + ], + }, + { + type: 'category', + label: 'Search', + items: [ + 'features/search/search-overview', + 'features/search/getting-started', + 'features/search/concepts', + 'features/search/architecture', + 'features/search/search-engines', + 'features/search/collators', + 'features/search/how-to-guides', + ], + }, { type: 'category', label: 'Software Catalog', @@ -61,19 +161,6 @@ module.exports = { 'features/software-catalog/faq', ], }, - { - type: 'category', - label: 'Kubernetes', - items: [ - 'features/kubernetes/overview', - 'features/kubernetes/installation', - 'features/kubernetes/configuration', - 'features/kubernetes/authentication', - 'features/kubernetes/authentication-strategies', - 'features/kubernetes/troubleshooting', - 'features/kubernetes/proxy', - ], - }, { type: 'category', label: 'Software Templates', @@ -92,19 +179,7 @@ module.exports = { 'features/software-templates/migrating-to-rjsf-v5', 'features/software-templates/migrating-from-v1beta2-to-v1beta3', 'features/software-templates/dry-run-testing', - ], - }, - { - type: 'category', - label: 'Backstage Search', - items: [ - 'features/search/search-overview', - 'features/search/getting-started', - 'features/search/concepts', - 'features/search/architecture', - 'features/search/search-engines', - 'features/search/collators', - 'features/search/how-to-guides', + 'features/software-templates/experimental', ], }, { @@ -138,6 +213,14 @@ module.exports = { 'integrations/aws-s3/discovery', ], }, + { + type: 'category', + label: 'Azure Blob Storage', + items: [ + 'integrations/azure-blobStorage/locations', + 'integrations/azure-blobStorage/discovery', + ], + }, { type: 'category', label: 'Azure', @@ -267,203 +350,142 @@ module.exports = { 'conf/writing', 'conf/defining', ], - Notifications: ['notifications/index'], - 'Auth and identity': [ - 'auth/index', + Framework: [ { type: 'category', - label: 'Included providers', + label: 'Backend System', items: [ - 'auth/auth0/provider', - 'auth/atlassian/provider', - 'auth/aws-alb/provider', - 'auth/microsoft/provider', - 'auth/microsoft/easy-auth', - 'auth/bitbucket/provider', - 'auth/bitbucketServer/provider', - 'auth/cloudflare/provider', - 'auth/github/provider', - 'auth/gitlab/provider', - 'auth/google/provider', - 'auth/google/gcp-iap-auth', - 'auth/guest/provider', - 'auth/okta/provider', - 'auth/oauth2-proxy/provider', - 'auth/onelogin/provider', - 'auth/vmware-cloud/provider', + 'backend-system/index', + { + type: 'category', + label: 'Architecture', + items: [ + 'backend-system/architecture/index', + 'backend-system/architecture/services', + 'backend-system/architecture/plugins', + 'backend-system/architecture/extension-points', + 'backend-system/architecture/modules', + 'backend-system/architecture/feature-loaders', + 'backend-system/architecture/naming-patterns', + ], + }, + { + type: 'category', + label: 'Building Backends', + items: [ + 'backend-system/building-backends/index', + 'backend-system/building-backends/migrating', + ], + }, + { + type: 'category', + label: 'Building Plugins & Modules', + items: [ + 'backend-system/building-plugins-and-modules/index', + 'backend-system/building-plugins-and-modules/testing', + 'backend-system/building-plugins-and-modules/migrating', + ], + }, + { + type: 'category', + label: 'Core Services', + items: [ + 'backend-system/core-services/index', + 'backend-system/core-services/auth', + 'backend-system/core-services/cache', + 'backend-system/core-services/database', + 'backend-system/core-services/discovery', + 'backend-system/core-services/http-auth', + 'backend-system/core-services/http-router', + 'backend-system/core-services/identity', + 'backend-system/core-services/lifecycle', + 'backend-system/core-services/logger', + 'backend-system/core-services/permissions', + 'backend-system/core-services/plugin-metadata', + 'backend-system/core-services/root-config', + 'backend-system/core-services/root-health', + 'backend-system/core-services/root-http-router', + 'backend-system/core-services/root-lifecycle', + 'backend-system/core-services/root-logger', + 'backend-system/core-services/scheduler', + 'backend-system/core-services/token-manager', + 'backend-system/core-services/url-reader', + 'backend-system/core-services/user-info', + ], + }, ], }, - 'auth/identity-resolver', - 'auth/oauth', - 'auth/oidc', - 'auth/add-auth-provider', - 'auth/service-to-service-auth', - 'auth/autologout', - 'auth/troubleshooting', - ], - Permissions: [ - 'permissions/overview', - 'permissions/concepts', - 'permissions/getting-started', - 'permissions/writing-a-policy', - 'permissions/frontend-integration', - 'permissions/custom-rules', { type: 'category', - label: 'Tutorial: using Permissions in your plugin', + label: 'New Frontend System', items: [ - 'permissions/plugin-authors/01-setup', - 'permissions/plugin-authors/02-adding-a-basic-permission-check', - 'permissions/plugin-authors/03-adding-a-resource-permission-check', - 'permissions/plugin-authors/04-authorizing-access-to-paginated-data', - 'permissions/plugin-authors/05-frontend-authorization', + 'frontend-system/index', + { + type: 'category', + label: 'Architecture', + items: [ + 'frontend-system/architecture/index', + 'frontend-system/architecture/app', + 'frontend-system/architecture/plugins', + 'frontend-system/architecture/extensions', + 'frontend-system/architecture/extension-blueprints', + 'frontend-system/architecture/extension-overrides', + 'frontend-system/architecture/references', + 'frontend-system/architecture/utility-apis', + 'frontend-system/architecture/routes', + 'frontend-system/architecture/naming-patterns', + 'frontend-system/architecture/migrations', + ], + }, + { + type: 'category', + label: 'Building Plugins', + items: [ + 'frontend-system/building-plugins/index', + 'frontend-system/building-plugins/testing', + 'frontend-system/building-plugins/common-extension-blueprints', + 'frontend-system/building-plugins/built-in-data-refs', + 'frontend-system/building-plugins/migrating', + ], + }, + { + type: 'category', + label: 'Building Apps', + items: [ + 'frontend-system/building-apps/index', + 'frontend-system/building-apps/configuring-extensions', + 'frontend-system/building-apps/built-in-extensions', + 'frontend-system/building-apps/plugin-conversion', + 'frontend-system/building-apps/migrating', + ], + }, + { + type: 'category', + label: 'Utility APIs', + items: [ + 'frontend-system/utility-apis/index', + 'frontend-system/utility-apis/creating', + 'frontend-system/utility-apis/consuming', + 'frontend-system/utility-apis/configuring', + ], + }, ], }, - ], - Tooling: [ { - type: 'category', - label: 'Backstage CLI', - items: [ + 'Backstage CLI': [ 'tooling/cli/overview', 'tooling/cli/build-system', 'tooling/cli/commands', - ], - }, - { - type: 'category', - label: 'Local Development', - items: [ - 'tooling/local-dev/linking-local-packages', - 'tooling/local-dev/debugging', - 'tooling/local-dev/profiling', - ], - }, - 'tooling/package-metadata', - ], - Deployment: [ - 'deployment/index', - 'deployment/scaling', - 'deployment/docker', - 'deployment/k8s', - 'deployment/heroku', - 'deployment/koyeb', - 'deployment/flightcontrol', - { - type: 'category', - label: 'Using Backstage Deploy (alpha)', - items: ['deployment/backstage-deploy/aws-lightsail'], - }, - ], - 'New Backend System': [ - 'backend-system/index', - { - type: 'category', - label: 'Architecture', - items: [ - 'backend-system/architecture/index', - 'backend-system/architecture/services', - 'backend-system/architecture/plugins', - 'backend-system/architecture/extension-points', - 'backend-system/architecture/modules', - 'backend-system/architecture/feature-loaders', - 'backend-system/architecture/naming-patterns', - ], - }, - { - type: 'category', - label: 'Building Backends', - items: [ - 'backend-system/building-backends/index', - 'backend-system/building-backends/migrating', - ], - }, - { - type: 'category', - label: 'Building Plugins & Modules', - items: [ - 'backend-system/building-plugins-and-modules/index', - 'backend-system/building-plugins-and-modules/testing', - 'backend-system/building-plugins-and-modules/migrating', - ], - }, - { - type: 'category', - label: 'Core Services', - items: [ - 'backend-system/core-services/index', - 'backend-system/core-services/auth', - 'backend-system/core-services/cache', - 'backend-system/core-services/database', - 'backend-system/core-services/discovery', - 'backend-system/core-services/http-auth', - 'backend-system/core-services/http-router', - 'backend-system/core-services/identity', - 'backend-system/core-services/lifecycle', - 'backend-system/core-services/logger', - 'backend-system/core-services/permissions', - 'backend-system/core-services/plugin-metadata', - 'backend-system/core-services/root-config', - 'backend-system/core-services/root-health', - 'backend-system/core-services/root-http-router', - 'backend-system/core-services/root-lifecycle', - 'backend-system/core-services/root-logger', - 'backend-system/core-services/scheduler', - 'backend-system/core-services/token-manager', - 'backend-system/core-services/url-reader', - 'backend-system/core-services/user-info', - ], - }, - ], - 'New Frontend System': [ - 'frontend-system/index', - { - type: 'category', - label: 'Architecture', - items: [ - 'frontend-system/architecture/index', - 'frontend-system/architecture/app', - 'frontend-system/architecture/plugins', - 'frontend-system/architecture/extensions', - 'frontend-system/architecture/extension-blueprints', - 'frontend-system/architecture/extension-overrides', - 'frontend-system/architecture/references', - 'frontend-system/architecture/utility-apis', - 'frontend-system/architecture/routes', - 'frontend-system/architecture/naming-patterns', - 'frontend-system/architecture/migrations', - ], - }, - { - type: 'category', - label: 'Building Plugins', - items: [ - 'frontend-system/building-plugins/index', - 'frontend-system/building-plugins/testing', - 'frontend-system/building-plugins/common-extension-blueprints', - 'frontend-system/building-plugins/built-in-data-refs', - 'frontend-system/building-plugins/migrating', - ], - }, - { - type: 'category', - label: 'Building Apps', - items: [ - 'frontend-system/building-apps/index', - 'frontend-system/building-apps/configuring-extensions', - 'frontend-system/building-apps/built-in-extensions', - 'frontend-system/building-apps/plugin-conversion', - 'frontend-system/building-apps/migrating', - ], - }, - { - type: 'category', - label: 'Utility APIs', - items: [ - 'frontend-system/utility-apis/index', - 'frontend-system/utility-apis/creating', - 'frontend-system/utility-apis/consuming', - 'frontend-system/utility-apis/configuring', + { + type: 'category', + label: 'Local Development', + items: [ + 'tooling/local-dev/linking-local-packages', + 'tooling/local-dev/debugging', + 'tooling/local-dev/profiling', + ], + }, + 'tooling/package-metadata', ], }, ], @@ -473,19 +495,6 @@ module.exports = { 'dls/contributing-to-storybook', 'dls/figma', ], - 'API Reference': [ - { - type: 'category', - label: 'Guides', - items: ['api/utility-apis'], - }, - { - type: 'category', - label: 'API Reference', - items: ['reference/index'], - }, - 'api/deprecations', - ], Tutorials: [ 'tutorials/quickstart-app-plugin', 'tutorials/react-router-stable-migration', @@ -501,22 +510,7 @@ module.exports = { 'tutorials/enable-public-entry', 'tutorials/setup-opentelemetry', ], - 'Architecture Decision Records (ADRs)': [ - 'architecture-decisions/adrs-overview', - 'architecture-decisions/adrs-adr001', - 'architecture-decisions/adrs-adr002', - 'architecture-decisions/adrs-adr003', - 'architecture-decisions/adrs-adr004', - 'architecture-decisions/adrs-adr005', - 'architecture-decisions/adrs-adr006', - 'architecture-decisions/adrs-adr007', - 'architecture-decisions/adrs-adr008', - 'architecture-decisions/adrs-adr009', - 'architecture-decisions/adrs-adr010', - 'architecture-decisions/adrs-adr011', - 'architecture-decisions/adrs-adr012', - 'architecture-decisions/adrs-adr013', - ], + FAQ: ['faq/index', 'faq/product', 'faq/technical'], Accessibility: ['accessibility/index'], Contribute: [ @@ -524,7 +518,33 @@ module.exports = { 'contribute/getting-involved', 'contribute/project-structure', ], - References: ['references/glossary'], + References: [ + { + type: 'category', + label: 'Architecture Decision Records (ADRs)', + items: [ + 'architecture-decisions/adrs-overview', + 'architecture-decisions/adrs-adr001', + 'architecture-decisions/adrs-adr002', + 'architecture-decisions/adrs-adr003', + 'architecture-decisions/adrs-adr004', + 'architecture-decisions/adrs-adr005', + 'architecture-decisions/adrs-adr006', + 'architecture-decisions/adrs-adr007', + 'architecture-decisions/adrs-adr008', + 'architecture-decisions/adrs-adr009', + 'architecture-decisions/adrs-adr010', + 'architecture-decisions/adrs-adr011', + 'architecture-decisions/adrs-adr012', + 'architecture-decisions/adrs-adr013', + 'architecture-decisions/adrs-adr014', + ], + }, + 'api/deprecations', + 'references/glossary', + 'api/utility-apis', + 'reference/index', + ], }, releases: { 'Release Notes': releases.map(release => `releases/${release}`), diff --git a/microsite/src/pages/plugins/_pluginCard.tsx b/microsite/src/pages/plugins/_pluginCard.tsx index ba8e8069d2..ba7864f9aa 100644 --- a/microsite/src/pages/plugins/_pluginCard.tsx +++ b/microsite/src/pages/plugins/_pluginCard.tsx @@ -9,14 +9,14 @@ export interface IPluginData { category: string; description: string; documentation: string; - iconUrl: string; + iconUrl?: string; title: string; addedDate: string; isNew: boolean; order?: number; } -const defaultIconUrl = 'img/logo-gradient-on-dark.svg'; +const defaultIconUrl = '/img/logo-gradient-on-dark.svg'; export const PluginCard = ({ author, diff --git a/microsite/static/img/synergy-logo.png b/microsite/static/img/synergy-logo.png new file mode 100644 index 0000000000..42eb59c704 Binary files /dev/null and b/microsite/static/img/synergy-logo.png differ diff --git a/microsite/yarn.lock b/microsite/yarn.lock index 93248d9dc2..6197b0463e 100644 --- a/microsite/yarn.lock +++ b/microsite/yarn.lock @@ -197,119 +197,132 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.8.3": - version: 7.26.2 - resolution: "@babel/code-frame@npm:7.26.2" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.8.3": + version: 7.24.7 + resolution: "@babel/code-frame@npm:7.24.7" dependencies: - "@babel/helper-validator-identifier": ^7.25.9 - js-tokens: ^4.0.0 + "@babel/highlight": ^7.24.7 picocolors: ^1.0.0 - checksum: db13f5c42d54b76c1480916485e6900748bbcb0014a8aca87f50a091f70ff4e0d0a6db63cade75eb41fcc3d2b6ba0a7f89e343def4f96f00269b41b8ab8dd7b8 + checksum: 830e62cd38775fdf84d612544251ce773d544a8e63df667728cc9e0126eeef14c6ebda79be0f0bc307e8318316b7f58c27ce86702e0a1f5c321d842eb38ffda4 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.9, @babel/compat-data@npm:^7.26.0": - version: 7.26.2 - resolution: "@babel/compat-data@npm:7.26.2" - checksum: d52fae9b0dc59b409d6005ae6b172e89329f46d68136130065ebe923a156fc633e0f1c8600b3e319b9e0f99fd948f64991a5419e2e9431d00d9d235d5f7a7618 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.2, @babel/compat-data@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/compat-data@npm:7.25.4" + checksum: b12a91d27c3731a4b0bdc9312a50b1911f41f7f728aaf0d4b32486e2257fd2cb2d3ea1a295e98449600c48f2c7883a3196ca77cda1cef7d97a10c2e83d037974 languageName: node linkType: hard -"@babel/core@npm:^7.21.3, @babel/core@npm:^7.25.9": - version: 7.26.0 - resolution: "@babel/core@npm:7.26.0" +"@babel/core@npm:^7.21.3, @babel/core@npm:^7.23.3": + version: 7.25.2 + resolution: "@babel/core@npm:7.25.2" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.26.0 - "@babel/generator": ^7.26.0 - "@babel/helper-compilation-targets": ^7.25.9 - "@babel/helper-module-transforms": ^7.26.0 - "@babel/helpers": ^7.26.0 - "@babel/parser": ^7.26.0 - "@babel/template": ^7.25.9 - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.26.0 + "@babel/code-frame": ^7.24.7 + "@babel/generator": ^7.25.0 + "@babel/helper-compilation-targets": ^7.25.2 + "@babel/helper-module-transforms": ^7.25.2 + "@babel/helpers": ^7.25.0 + "@babel/parser": ^7.25.0 + "@babel/template": ^7.25.0 + "@babel/traverse": ^7.25.2 + "@babel/types": ^7.25.2 convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.3 semver: ^6.3.1 - checksum: b296084cfd818bed8079526af93b5dfa0ba70282532d2132caf71d4060ab190ba26d3184832a45accd82c3c54016985a4109ab9118674347a7e5e9bc464894e6 + checksum: 9a1ef604a7eb62195f70f9370cec45472a08114e3934e3eaaedee8fd754edf0730e62347c7b4b5e67d743ce57b5bb8cf3b92459482ca94d06e06246ef021390a languageName: node linkType: hard -"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0": - version: 7.26.2 - resolution: "@babel/generator@npm:7.26.2" +"@babel/generator@npm:^7.23.3, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.4": + version: 7.25.5 + resolution: "@babel/generator@npm:7.25.5" dependencies: - "@babel/parser": ^7.26.2 - "@babel/types": ^7.26.0 + "@babel/types": ^7.25.4 "@jridgewell/gen-mapping": ^0.3.5 "@jridgewell/trace-mapping": ^0.3.25 - jsesc: ^3.0.2 - checksum: 6ff850b7d6082619f8c2f518d993cf7254cfbaa20b026282cbef5c9b2197686d076a432b18e36c4d1a42721c016df4f77a8f62c67600775d9683621d534b91b4 + jsesc: ^2.5.1 + checksum: d7713f02536a8144eca810e9b13ae854b05fec462348eaf52e7b50df2c0a312bc43bfff0e8e10d6dd982e8986d61175ac8e67d7358a8b4dad9db4d6733bf0c9c languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" +"@babel/helper-annotate-as-pure@npm:^7.22.5, @babel/helper-annotate-as-pure@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" dependencies: - "@babel/types": ^7.25.9 - checksum: 41edda10df1ae106a9b4fe617bf7c6df77db992992afd46192534f5cff29f9e49a303231733782dd65c5f9409714a529f215325569f14282046e9d3b7a1ffb6c + "@babel/types": ^7.24.7 + checksum: 6178566099a6a0657db7a7fa601a54fb4731ca0b8614fbdccfd8e523c210c13963649bc8fdfd53ce7dd14d05e3dda2fb22dea5b30113c488b9eb1a906d60212e languageName: node linkType: hard -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.25.9" +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.7" dependencies: - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: e1bb465b3b0155702d82cfef09e3813e87a6d777cdd2c513796861eac14953340491eafea1d4109278bf4ceb48b54074c45758f042c0544d00c498090bee5a6f + "@babel/traverse": ^7.24.7 + "@babel/types": ^7.24.7 + checksum: 71a6158a9fdebffb82fdc400d5555ba8f2e370cea81a0d578155877bdc4db7d5252b75c43b2fdf3f72b3f68348891f99bd35ae315542daad1b7ace8322b1abcb languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-compilation-targets@npm:7.25.9" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7, @babel/helper-compilation-targets@npm:^7.24.8, @babel/helper-compilation-targets@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-compilation-targets@npm:7.25.2" dependencies: - "@babel/compat-data": ^7.25.9 - "@babel/helper-validator-option": ^7.25.9 - browserslist: ^4.24.0 + "@babel/compat-data": ^7.25.2 + "@babel/helper-validator-option": ^7.24.8 + browserslist: ^4.23.1 lru-cache: ^5.1.1 semver: ^6.3.1 - checksum: 3af536e2db358b38f968abdf7d512d425d1018fef2f485d6f131a57a7bcaed32c606b4e148bb230e1508fa42b5b2ac281855a68eb78270f54698c48a83201b9b + checksum: aed33c5496cb9db4b5e2d44e26bf8bc474074cc7f7bb5ebe1d4a20fdeb362cb3ba9e1596ca18c7484bcd6e5c3a155ab975e420d520c0ae60df81f9de04d0fd16 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" +"@babel/helper-create-class-features-plugin@npm:^7.24.7, @babel/helper-create-class-features-plugin@npm:^7.25.0, @babel/helper-create-class-features-plugin@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-member-expression-to-functions": ^7.25.9 - "@babel/helper-optimise-call-expression": ^7.25.9 - "@babel/helper-replace-supers": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.24.7 + "@babel/helper-member-expression-to-functions": ^7.24.8 + "@babel/helper-optimise-call-expression": ^7.24.7 + "@babel/helper-replace-supers": ^7.25.0 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 + "@babel/traverse": ^7.25.4 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: 91dd5f203ed04568c70b052e2f26dfaac7c146447196c00b8ecbb6d3d2f3b517abadb985d3321a19d143adaed6fe17f7f79f8f50e0c20e9d8ad83e1027b42424 + checksum: 4544ebda4516eb25efdebd47ca024bd7bdb1eb6e7cc3ad89688c8ef8e889734c2f4411ed78981899c641394f013f246f2af63d92a0e9270f6c453309b4cb89ba languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.9" +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7, @babel/helper-create-regexp-features-plugin@npm:^7.25.0, @babel/helper-create-regexp-features-plugin@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - regexpu-core: ^6.1.1 + "@babel/helper-annotate-as-pure": ^7.24.7 + regexpu-core: ^5.3.1 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: 563ed361ceed3d7a9d64dd58616bf6f0befcc23620ab22d31dd6d8b751d3f99d6d210487b1a5a1e209ab4594df67bacfab7445cbfa092bfe2b719cd42ae1ba6f + checksum: df55fdc6a1f3090dd37d91347df52d9322d52affa239543808dc142f8fe35e6787e67d8612337668198fac85826fafa9e6772e6c28b7d249ec94e6fafae5da6e + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.4.2": + version: 0.4.2 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.2" + dependencies: + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 1f6dec0c5d0876d278fe15b71238eccc5f74c4e2efa2c78aaafa8bc2cc96336b8e68d94cd1a78497356c96e8b91b8c1f4452179820624d1702aee2f9832e6569 languageName: node linkType: hard @@ -328,210 +341,223 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" +"@babel/helper-member-expression-to-functions@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" dependencies: - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: 8e2f1979b6d596ac2a8cbf17f2cf709180fefc274ac3331408b48203fe19134ed87800774ef18838d0275c3965130bae22980d90caed756b7493631d4b2cf961 + "@babel/traverse": ^7.24.8 + "@babel/types": ^7.24.8 + checksum: bf923d05d81b06857f4ca4fe9c528c9c447a58db5ea39595bb559eae2fce01a8266173db0fd6a2ec129d7bbbb9bb22f4e90008252f7c66b422c76630a878a4bc languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-module-imports@npm:7.25.9" +"@babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-module-imports@npm:7.24.7" dependencies: - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: 1b411ce4ca825422ef7065dffae7d8acef52023e51ad096351e3e2c05837e9bf9fca2af9ca7f28dc26d596a588863d0fedd40711a88e350b736c619a80e704e6 + "@babel/traverse": ^7.24.7 + "@babel/types": ^7.24.7 + checksum: 8ac15d96d262b8940bc469052a048e06430bba1296369be695fabdf6799f201dd0b00151762b56012a218464e706bc033f27c07f6cec20c6f8f5fd6543c67054 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.25.9, @babel/helper-module-transforms@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/helper-module-transforms@npm:7.26.0" +"@babel/helper-module-transforms@npm:^7.24.7, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0, @babel/helper-module-transforms@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-module-transforms@npm:7.25.2" dependencies: - "@babel/helper-module-imports": ^7.25.9 - "@babel/helper-validator-identifier": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-module-imports": ^7.24.7 + "@babel/helper-simple-access": ^7.24.7 + "@babel/helper-validator-identifier": ^7.24.7 + "@babel/traverse": ^7.25.2 peerDependencies: "@babel/core": ^7.0.0 - checksum: 942eee3adf2b387443c247a2c190c17c4fd45ba92a23087abab4c804f40541790d51ad5277e4b5b1ed8d5ba5b62de73857446b7742f835c18ebd350384e63917 + checksum: 282d4e3308df6746289e46e9c39a0870819630af5f84d632559171e4fae6045684d771a65f62df3d569e88ccf81dc2def78b8338a449ae3a94bb421aa14fc367 languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" +"@babel/helper-optimise-call-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" dependencies: - "@babel/types": ^7.25.9 - checksum: f09d0ad60c0715b9a60c31841b3246b47d67650c512ce85bbe24a3124f1a4d66377df793af393273bc6e1015b0a9c799626c48e53747581c1582b99167cc65dc + "@babel/types": ^7.24.7 + checksum: 280654eaf90e92bf383d7eed49019573fb35a98c9e992668f701ad099957246721044be2068cf6840cb2299e0ad393705a1981c88c23a1048096a8d59e5f79a3 languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.25.9 - resolution: "@babel/helper-plugin-utils@npm:7.25.9" - checksum: e19ec8acf0b696756e6d84531f532c5fe508dce57aa68c75572a77798bd04587a844a9a6c8ea7d62d673e21fdc174d091c9097fb29aea1c1b49f9c6eaa80f022 +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.8 + resolution: "@babel/helper-plugin-utils@npm:7.24.8" + checksum: 73b1a83ba8bcee21dc94de2eb7323207391715e4369fd55844bb15cf13e3df6f3d13a40786d990e6370bf0f571d94fc31f70dec96c1d1002058258c35ca3767a languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-remap-async-to-generator@npm:7.25.9" +"@babel/helper-remap-async-to-generator@npm:^7.24.7, @babel/helper-remap-async-to-generator@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-wrap-function": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.24.7 + "@babel/helper-wrap-function": ^7.25.0 + "@babel/traverse": ^7.25.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: ea37ad9f8f7bcc27c109963b8ebb9d22bac7a5db2a51de199cb560e251d5593fe721e46aab2ca7d3e7a24b0aa4aff0eaf9c7307af9c2fd3a1d84268579073052 + checksum: 47f3065e43fe9d6128ddb4291ffb9cf031935379265fd13de972b5f241943121f7583efb69cd2e1ecf39e3d0f76f047547d56c3fcc2c853b326fad5465da0bd7 languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-replace-supers@npm:7.25.9" +"@babel/helper-replace-supers@npm:^7.24.7, @babel/helper-replace-supers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-replace-supers@npm:7.25.0" dependencies: - "@babel/helper-member-expression-to-functions": ^7.25.9 - "@babel/helper-optimise-call-expression": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-member-expression-to-functions": ^7.24.8 + "@babel/helper-optimise-call-expression": ^7.24.7 + "@babel/traverse": ^7.25.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: 84f40e12520b7023e52d289bf9d569a06284879fe23bbbacad86bec5d978b2669769f11b073fcfeb1567d8c547168323005fda88607a4681ecaeb4a5cdd48bb9 + checksum: f669fc2487c22d40b808f94b9c3ee41129484d5ef0ba689bdd70f216ff91e10b6b021d2f8cd37e7bdd700235a2a6ae6622526344f064528190383bf661ac65f8 languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-simple-access@npm:7.25.9" +"@babel/helper-simple-access@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-simple-access@npm:7.24.7" dependencies: - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: 6d96c94b88e8288d15e5352c1221486bd4f62de8c7dc7c7b9f5b107ce2c79f67fec5ed71a0476e146f1fefbbbf1d69abe35dc821d80ce01fc7f472286c342421 + "@babel/traverse": ^7.24.7 + "@babel/types": ^7.24.7 + checksum: ddbf55f9dea1900213f2a1a8500fabfd21c5a20f44dcfa957e4b0d8638c730f88751c77f678644f754f1a1dc73f4eb8b766c300deb45a9daad000e4247957819 languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" dependencies: - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: fdbb5248932198bc26daa6abf0d2ac42cab9c2dbb75b7e9f40d425c8f28f09620b886d40e7f9e4e08ffc7aaa2cefe6fc2c44be7c20e81f7526634702fb615bdc + "@babel/traverse": ^7.24.7 + "@babel/types": ^7.24.7 + checksum: 11b28fe534ce2b1a67c4d8e51a7b5711a2a0a0cae802f74614eee54cca58c744d9a62f6f60103c41759e81c537d270bfd665bf368a6bea214c6052f2094f8407 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-string-parser@npm:7.25.9" - checksum: 6435ee0849e101681c1849868278b5aee82686ba2c1e27280e5e8aca6233af6810d39f8e4e693d2f2a44a3728a6ccfd66f72d71826a94105b86b731697cdfa99 +"@babel/helper-string-parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-string-parser@npm:7.24.8" + checksum: 39b03c5119216883878655b149148dc4d2e284791e969b19467a9411fccaa33f7a713add98f4db5ed519535f70ad273cdadfd2eb54d47ebbdeac5083351328ce languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-identifier@npm:7.25.9" - checksum: 5b85918cb1a92a7f3f508ea02699e8d2422fe17ea8e82acd445006c0ef7520fbf48e3dbcdaf7b0a1d571fc3a2715a29719e5226636cb6042e15fe6ed2a590944 +"@babel/helper-validator-identifier@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-identifier@npm:7.24.7" + checksum: 6799ab117cefc0ecd35cd0b40ead320c621a298ecac88686a14cffceaac89d80cdb3c178f969861bf5fa5e4f766648f9161ea0752ecfe080d8e89e3147270257 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-validator-option@npm:7.25.9" - checksum: 9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d +"@babel/helper-validator-option@npm:^7.22.15, @babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-validator-option@npm:7.24.8" + checksum: a52442dfa74be6719c0608fee3225bd0493c4057459f3014681ea1a4643cd38b68ff477fe867c4b356da7330d085f247f0724d300582fa4ab9a02efaf34d107c languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/helper-wrap-function@npm:7.25.9" +"@babel/helper-wrap-function@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-wrap-function@npm:7.25.0" dependencies: - "@babel/template": ^7.25.9 - "@babel/traverse": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: 8ec1701e60ae004415800c4a7a188f5564c73b4e4f3fdf58dd3f34a3feaa9753173f39bbd6d02e7ecc974f48155efc7940e62584435b3092c07728ee46a604ea + "@babel/template": ^7.25.0 + "@babel/traverse": ^7.25.0 + "@babel/types": ^7.25.0 + checksum: 0095b4741704066d1687f9bbd5370bb88c733919e4275e49615f70c180208148ff5f24ab58d186ce92f8f5d28eab034ec6617e9264590cc4744c75302857629c languageName: node linkType: hard -"@babel/helpers@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/helpers@npm:7.26.0" +"@babel/helpers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helpers@npm:7.25.0" dependencies: - "@babel/template": ^7.25.9 - "@babel/types": ^7.26.0 - checksum: d77fe8d45033d6007eadfa440355c1355eed57902d5a302f450827ad3d530343430a21210584d32eef2f216ae463d4591184c6fc60cf205bbf3a884561469200 + "@babel/template": ^7.25.0 + "@babel/types": ^7.25.0 + checksum: 739e3704ff41a30f5eaac469b553f4d3ab02be6ced083f5925851532dfbd9efc5c347728e77b754ed0b262a4e5e384e60932a62c192d338db7e4b7f3adf9f4a7 languageName: node linkType: hard -"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2": - version: 7.26.2 - resolution: "@babel/parser@npm:7.26.2" +"@babel/highlight@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/highlight@npm:7.24.7" dependencies: - "@babel/types": ^7.26.0 + "@babel/helper-validator-identifier": ^7.24.7 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + picocolors: ^1.0.0 + checksum: 5cd3a89f143671c4ac129960024ba678b669e6fc673ce078030f5175002d1d3d52bc10b22c5b916a6faf644b5028e9a4bd2bb264d053d9b05b6a98690f1d46f1 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/parser@npm:7.25.4" + dependencies: + "@babel/types": ^7.25.4 bin: parser: ./bin/babel-parser.js - checksum: c88b5ea0adf357ef909cdc2c31e284a154943edc59f63f6e8a4c20bf773a1b2f3d8c2205e59c09ca7cdad91e7466300114548876529277a80651b6436a48d5d9 + checksum: fe4f083d4ad34f019dd7fad672cd007003004fb0a3df9b7315a5da9a5e8e56c1fed95acab6862e7d76cfccb2e8e364bcc307e9117718e6bb6dfb2e87ad065abf languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.3": + version: 7.25.3 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.3" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/traverse": ^7.25.3 peerDependencies: "@babel/core": ^7.0.0 - checksum: b33d37dacf98a9c74f53959999adc37a258057668b62dba557e6865689433c53764673109eaba9102bf73b2ac4db162f0d9b89a6cca6f1b71d12f5908ec11da9 + checksum: d3dba60f360defe70eb43e35a1b17ea9dd4a99e734249e15be3d5c288019644f96f88d7ff51990118fda0845b4ad50f6d869e0382232b1d8b054d113d4eea7e2 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.9" +"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0 - checksum: d3e14ab1cb9cb50246d20cab9539f2fbd1e7ef1ded73980c8ad7c0561b4d5e0b144d362225f0976d47898e04cbd40f2000e208b0913bd788346cf7791b96af91 + checksum: fd56d1e6435f2c008ca9050ea906ff7eedcbec43f532f2bf2e7e905d8bf75bf5e4295ea9593f060394e2c8e45737266ccbf718050bad2dd7be4e7613c60d1b5b languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.9" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0 - checksum: a9d1ee3fd100d3eb6799a2f2bbd785296f356c531d75c9369f71541811fa324270258a374db103ce159156d006da2f33370330558d0133e6f7584152c34997ca + checksum: 13ed301b108d85867d64226bbc4032b07dd1a23aab68e9e32452c4fe3930f2198bb65bdae9c262c4104bd5e45647bc1830d25d43d356ee9a137edd8d5fab8350 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.25.9" +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 - "@babel/plugin-transform-optional-chaining": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 + "@babel/plugin-transform-optional-chaining": ^7.24.7 peerDependencies: "@babel/core": ^7.13.0 - checksum: 5b298b28e156f64de51cdb03a2c5b80c7f978815ef1026f3ae8b9fc48d28bf0a83817d8fbecb61ef8fb94a7201f62cca5103cc6e7b9e8f28e38f766d7905b378 + checksum: 07b92878ac58a98ea1fdf6a8b4ec3413ba4fa66924e28b694d63ec5b84463123fbf4d7153b56cf3cedfef4a3482c082fe3243c04f8fb2c041b32b0e29b4a9e21 languageName: node linkType: hard -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.9" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/traverse": ^7.25.0 peerDependencies: "@babel/core": ^7.0.0 - checksum: c684593952ab1b40dfa4e64e98a07e7227c6db175c21bd0e6d71d2ad5d240fef4e4a984d56f05a494876542a022244fe1c1098f4116109fd90d06615e8a269b1 + checksum: c8d08b8d6cc71451ad2a50cf7db72ab5b41c1e5e2e4d56cf6837a25a61270abd682c6b8881ab025f11a552d2024b3780519bb051459ebb71c27aed13d9917663 languageName: node linkType: hard @@ -544,6 +570,39 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-syntax-async-generators@npm:^7.8.4": + version: 7.8.4 + resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.13": + version: 7.12.13 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" + dependencies: + "@babel/helper-plugin-utils": ^7.12.13 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + "@babel/plugin-syntax-dynamic-import@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" @@ -555,47 +614,168 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-assertions@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/plugin-syntax-import-assertions@npm:7.26.0" +"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b58f2306df4a690ca90b763d832ec05202c50af787158ff8b50cdf3354359710bce2e1eb2b5135fcabf284756ac8eadf09ca74764aa7e76d12a5cac5f6b21e67 + checksum: 85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a languageName: node linkType: hard -"@babel/plugin-syntax-import-attributes@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" +"@babel/plugin-syntax-import-assertions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c122aa577166c80ee67f75aebebeef4150a132c4d3109d25d7fc058bf802946f883e330f20b78c1d3e3a5ada631c8780c263d2d01b5dbaecc69efefeedd42916 + checksum: c4d67be4eb1d4637e361477dbe01f5b392b037d17c1f861cfa0faa120030e137aab90a9237931b8040fd31d1e5d159e11866fa1165f78beef7a3be876a391a17 languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-syntax-jsx@npm:7.25.9" +"@babel/plugin-syntax-import-attributes@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bb609d1ffb50b58f0c1bac8810d0e46a4f6c922aa171c458f3a19d66ee545d36e782d3bffbbc1fed0dc65a558bdce1caf5279316583c0fff5a2c1658982a8563 + checksum: 590dbb5d1a15264f74670b427b8d18527672c3d6c91d7bae7e65f80fd810edbc83d90e68065088644cbad3f2457ed265a54a9956fb789fcb9a5b521822b3a275 languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" +"@babel/plugin-syntax-import-meta@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 + checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b + languageName: node + linkType: hard + +"@babel/plugin-syntax-json-strings@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a + languageName: node + linkType: hard + +"@babel/plugin-syntax-jsx@npm:^7.22.5, @babel/plugin-syntax-jsx@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": ^7.24.7 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7a5ca629d8ca1e1ee78705a78e58c12920d07ed8006d7e7232b31296a384ff5e41d7b649bde5561196041037bbb9f9715be1d1c20975df87ca204f34ad15b965 + languageName: node + linkType: hard + +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: aff33577037e34e515911255cdbb1fd39efee33658aa00b8a5fd3a4b903585112d037cce1cc9e4632f0487dc554486106b79ccd5ea63a2e00df4363f6d4ff886 + languageName: node + linkType: hard + +"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-chaining@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 + languageName: node + linkType: hard + +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": ^7.14.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.24.7": + version: 7.25.4 + resolution: "@babel/plugin-syntax-typescript@npm:7.25.4" + dependencies: + "@babel/helper-plugin-utils": ^7.24.8 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9b89b8930cd5983f64251d75c9fcdc17a8dc73837d6de12220ff972888ecff4054a6467cf0c423cad242aa96c0f0564a39a0823073728cc02239b80d13f02230 languageName: node linkType: hard @@ -611,454 +791,466 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-arrow-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.25.9" +"@babel/plugin-transform-arrow-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c29f081224859483accf55fb4d091db2aac0dcd0d7954bac5ca889030cc498d3f771aa20eb2e9cd8310084ec394d85fa084b97faf09298b6bc9541182b3eb5bb + checksum: 707c209b5331c7dc79bd326128c6a6640dbd62a78da1653c844db20c4f36bf7b68454f1bc4d2d051b3fde9136fa291f276ec03a071bb00ee653069ff82f91010 languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.9" +"@babel/plugin-transform-async-generator-functions@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.4" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-remap-async-to-generator": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-remap-async-to-generator": ^7.25.0 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/traverse": ^7.25.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 41e02c18c2a57de9f274fa2c5a1bf81a20ab5f321db29cc3051512b9c5bdf3f1a8c42f1fc282cb62343c6d50849f992eede954d5f7fb5e7df48ae0c59ea7e054 + checksum: 4235444735a1946f8766fe56564a8134c2c36c73e6cf83b3f2ed5624ebc84ff5979506a6a5b39acdb23aa09d442a6af471710ed408ccce533a2c4d2990b9df6a languageName: node linkType: hard -"@babel/plugin-transform-async-to-generator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.25.9" +"@babel/plugin-transform-async-to-generator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.7" dependencies: - "@babel/helper-module-imports": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-remap-async-to-generator": ^7.25.9 + "@babel/helper-module-imports": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-remap-async-to-generator": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b3ad50fb93c171644d501864620ed23952a46648c4df10dc9c62cc9ad08031b66bd272cfdd708faeee07c23b6251b16f29ce0350473e4c79f0c32178d38ce3a6 + checksum: 13704fb3b83effc868db2b71bfb2c77b895c56cb891954fc362e95e200afd523313b0e7cf04ce02f45b05e76017c5b5fa8070c92613727a35131bb542c253a36 languageName: node linkType: hard -"@babel/plugin-transform-block-scoped-functions@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.25.9" +"@babel/plugin-transform-block-scoped-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bf31896556b33a80f017af3d445ceb532ec0f5ca9d69bc211a963ac92514d172d5c24c5ac319f384d9dfa7f1a4d8dc23032c2fe3e74f98a59467ecd86f7033ae + checksum: 249cdcbff4e778b177245f9652b014ea4f3cd245d83297f10a7bf6d97790074089aa62bcde8c08eb299c5e68f2faed346b587d3ebac44d625ba9a83a4ee27028 languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-block-scoping@npm:7.25.9" +"@babel/plugin-transform-block-scoping@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e869500cfb1995e06e64c9608543b56468639809febfcdd6fcf683bc0bf1be2431cacf2981a168a1a14f4766393e37bc9f7c96d25bc5b5f39a64a8a8ad0bf8e0 + checksum: b1a8f932f69ad2a47ae3e02b4cedd2a876bfc2ac9cf72a503fd706cdc87272646fe9eed81e068c0fc639647033de29f7fa0c21cddd1da0026f83dbaac97316a8 languageName: node linkType: hard -"@babel/plugin-transform-class-properties@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-class-properties@npm:7.25.9" +"@babel/plugin-transform-class-properties@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/plugin-transform-class-properties@npm:7.25.4" dependencies: - "@babel/helper-create-class-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-class-features-plugin": ^7.25.4 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a8d69e2c285486b63f49193cbcf7a15e1d3a5f632c1c07d7a97f65306df7f554b30270b7378dde143f8b557d1f8f6336c643377943dec8ec405e4cd11e90b9ea + checksum: b73f7d968639c6c2dfc13f4c5a8fe45cefd260f0faa7890ae12e65d41211072544ff5e128c8b61a86887b29ffd3df8422dbdfbf61648488e71d4bb599c41f4a5 languageName: node linkType: hard -"@babel/plugin-transform-class-static-block@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/plugin-transform-class-static-block@npm:7.26.0" +"@babel/plugin-transform-class-static-block@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.7" dependencies: - "@babel/helper-create-class-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-class-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-class-static-block": ^7.14.5 peerDependencies: "@babel/core": ^7.12.0 - checksum: d779d4d3a6f8d363f67fcbd928c15baa72be8d3b86c6d05e0300b50e66e2c4be9e99398b803d13064bc79d90ae36e37a505e3dc8af11904459804dec07660246 + checksum: 324049263504f18416f1c3e24033baebfafd05480fdd885c8ebe6f2b415b0fc8e0b98d719360f9e30743cc78ac387fabc0b3c6606d2b54135756ffb92963b382 languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-classes@npm:7.25.9" +"@babel/plugin-transform-classes@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/plugin-transform-classes@npm:7.25.4" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-compilation-targets": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-replace-supers": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.24.7 + "@babel/helper-compilation-targets": ^7.25.2 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-replace-supers": ^7.25.0 + "@babel/traverse": ^7.25.4 globals: ^11.1.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d12584f72125314cc0fa8c77586ece2888d677788ac75f7393f5da574dfe4e45a556f7e3488fab29c8777ab3e5856d7a2d79f6df02834083aaa9d766440e3c68 + checksum: 0bf20e46eeb691bd60cee5d1b01950fc37accec88018ecace25099f7c8d8509c1ac54d11b8caf9f2157c6945969520642a3bc421159c1a14e80224dc9a7611de languageName: node linkType: hard -"@babel/plugin-transform-computed-properties@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-computed-properties@npm:7.25.9" +"@babel/plugin-transform-computed-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-computed-properties@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/template": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/template": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f77fa4bc0c1e0031068172df28852388db6b0f91c268d037905f459607cf1e8ebab00015f9f179f4ad96e11c5f381b635cd5dc4e147a48c7ac79d195ae7542de + checksum: 0cf8c1b1e4ea57dec8d4612460d84fd4cdbf71a7499bb61ee34632cf89018a59eee818ffca88a8d99ee7057c20a4257044d7d463fda6daef9bf1db9fa81563cb languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-destructuring@npm:7.25.9" +"@babel/plugin-transform-destructuring@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 965f63077a904828f4adee91393f83644098533442b8217d5a135c23a759a4c252c714074c965676a60d2c33f610f579a4eeb59ffd783724393af61c0ca45fef + checksum: 0b4bd3d608979a1e5bd97d9d42acd5ad405c7fffa61efac4c7afd8e86ea6c2d91ab2d94b6a98d63919571363fe76e0b03c4ff161f0f60241b895842596e4a999 languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.25.9" +"@babel/plugin-transform-dotall-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8bdf1bb9e6e3a2cc8154ae88a3872faa6dc346d6901994505fb43ac85f858728781f1219f40b67f7bb0687c507450236cb7838ac68d457e65637f98500aa161b + checksum: 67b10fc6abb1f61f0e765288eb4c6d63d1d0f9fc0660e69f6f2170c56fa16bc74e49857afc644beda112b41771cd90cf52df0940d11e97e52617c77c7dcff171 languageName: node linkType: hard -"@babel/plugin-transform-duplicate-keys@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.25.9" +"@babel/plugin-transform-duplicate-keys@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b553eebc328797ead6be5ba5bdaf2f1222cea8a5bd33fb4ed625975d4f9b510bfb0d688d97e314cd4b4a48b279bea7b3634ad68c1b41ee143c3082db0ae74037 + checksum: d1da2ff85ecb56a63f4ccfd9dc9ae69400d85f0dadf44ecddd9e71c6e5c7a9178e74e3a9637555f415a2bb14551e563f09f98534ab54f53d25e8439fdde6ba2d languageName: node linkType: hard -"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.9" +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.0" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.25.0 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0 - checksum: f7233cf596be8c6843d31951afaf2464a62a610cb89c72c818c044765827fab78403ab8a7d3a6386f838c8df574668e2a48f6c206b1d7da965aff9c6886cb8e6 + checksum: 608d6b0e77341189508880fd1a9f605a38d0803dd6f678ea3920ab181b17b377f6d5221ae8cf0104c7a044d30d4ddb0366bd064447695671d78457a656bb264f languageName: node linkType: hard -"@babel/plugin-transform-dynamic-import@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.25.9" +"@babel/plugin-transform-dynamic-import@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: aaca1ccda819be9b2b85af47ba08ddd2210ff2dbea222f26e4cd33f97ab020884bf81a66197e50872721e9daf36ceb5659502c82199884ea74d5d75ecda5c58b + checksum: 776509ff62ab40c12be814a342fc56a5cc09b91fb63032b2633414b635875fd7da03734657be0f6db2891fe6e3033b75d5ddb6f2baabd1a02e4443754a785002 languageName: node linkType: hard -"@babel/plugin-transform-exponentiation-operator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.25.9" +"@babel/plugin-transform-exponentiation-operator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.7" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 57e1bb4135dd16782fe84b49dd360cce8f9bf5f62eb10424dcdaf221e54a8bacdf50f2541c5ac01dea9f833a6c628613d71be915290938a93454389cba4de06b + checksum: 23c84a23eb56589fdd35a3540f9a1190615be069110a2270865223c03aee3ba4e0fc68fe14850800cf36f0712b26e4964d3026235261f58f0405a29fe8dac9b1 languageName: node linkType: hard -"@babel/plugin-transform-export-namespace-from@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.25.9" +"@babel/plugin-transform-export-namespace-from@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4dfe8df86c5b1d085d591290874bb2d78a9063090d71567ed657a418010ad333c3f48af2c974b865f53bbb718987a065f89828d43279a7751db1a56c9229078d + checksum: 3bd3a10038f10ae0dea1ee42137f3edcf7036b5e9e570a0d1cbd0865f03658990c6c2d84fa2475f87a754e7dc5b46766c16f7ce5c9b32c3040150b6a21233a80 languageName: node linkType: hard -"@babel/plugin-transform-for-of@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-for-of@npm:7.25.9" +"@babel/plugin-transform-for-of@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-for-of@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 41b56e70256a29fc26ed7fb95ece062d7ec2f3b6ea8f0686349ffd004cd4816132085ee21165b89c502ee7161cb7cfb12510961638851357945dc7bc546475b7 + checksum: a53b42dc93ab4b7d1ebd3c695b52be22b3d592f6a3dbdb3dc2fea2c8e0a7e1508fe919864c455cde552aec44ce7518625fccbb70c7063373ca228d884f4f49ea languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-function-name@npm:7.25.9" +"@babel/plugin-transform-function-name@npm:^7.25.1": + version: 7.25.1 + resolution: "@babel/plugin-transform-function-name@npm:7.25.1" dependencies: - "@babel/helper-compilation-targets": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-compilation-targets": ^7.24.8 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/traverse": ^7.25.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a8d7c8d019a6eb57eab5ca1be3e3236f175557d55b1f3b11f8ad7999e3fbb1cf37905fd8cb3a349bffb4163a558e9f33b63f631597fdc97c858757deac1b2fd7 + checksum: 743f3ea03bbc5a90944849d5a880b6bd9243dddbde581a46952da76e53a0b74c1e2424133fe8129d7a152c1f8c872bcd27e0b6728d7caadabd1afa7bb892e1e0 languageName: node linkType: hard -"@babel/plugin-transform-json-strings@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-json-strings@npm:7.25.9" +"@babel/plugin-transform-json-strings@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-json-strings": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e2498d84761cfd05aaea53799933d55af309c9d6204e66b38778792d171e4d1311ad34f334259a3aa3407dd0446f6bd3e390a1fcb8ce2e42fe5aabed0e41bee1 + checksum: 88874d0b7a1ddea66c097fc0abb68801ffae194468aa44b828dde9a0e20ac5d8647943793de86092eabaa2911c96f67a6b373793d4bb9c932ef81b2711c06c2e languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-literals@npm:7.25.9" +"@babel/plugin-transform-literals@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/plugin-transform-literals@npm:7.25.2" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3cca75823a38aab599bc151b0fa4d816b5e1b62d6e49c156aa90436deb6e13649f5505973151a10418b64f3f9d1c3da53e38a186402e0ed7ad98e482e70c0c14 + checksum: 70c9bb40e377a306bd8f500899fb72127e527517914466e95dc6bb53fa7a0f51479db244a54a771b5780fc1eab488fedd706669bf11097b81a23c81ab7423eb1 languageName: node linkType: hard -"@babel/plugin-transform-logical-assignment-operators@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.25.9" +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8c6febb4ac53852314d28b5e2c23d5dbbff7bf1e57d61f9672e0d97531ef7778b3f0ad698dcf1179f5486e626c77127508916a65eb846a89e98a92f70ed3537b + checksum: 3367ce0be243704dc6fce23e86a592c4380f01998ee5dd9f94c54b1ef7b971ac6f8a002901eb51599ac6cbdc0d067af8d1a720224fca1c40fde8bb8aab804aac languageName: node linkType: hard -"@babel/plugin-transform-member-expression-literals@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.25.9" +"@babel/plugin-transform-member-expression-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: db92041ae87b8f59f98b50359e0bb172480f6ba22e5e76b13bdfe07122cbf0daa9cd8ad2e78dcb47939938fed88ad57ab5989346f64b3a16953fc73dea3a9b1f + checksum: 2720c57aa3bf70576146ba7d6ea03227f4611852122d76d237924f7b008dafc952e6ae61a19e5024f26c665f44384bbd378466f01b6bd1305b3564a3b7fb1a5d languageName: node linkType: hard -"@babel/plugin-transform-modules-amd@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-modules-amd@npm:7.25.9" +"@babel/plugin-transform-modules-amd@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-amd@npm:7.24.7" dependencies: - "@babel/helper-module-transforms": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-module-transforms": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: baad1f6fd0e0d38e9a9c1086a06abdc014c4c653fd452337cadfe23fb5bd8bf4368d1bc433a5ac8e6421bc0732ebb7c044cf3fb39c1b7ebe967d66e26c4e5cec + checksum: f1dd0fb2f46c0f8f21076b8c7ccd5b33a85ce6dcb31518ea4c648d9a5bb2474cd4bd87c9b1b752e68591e24b022e334ba0d07631fef2b6b4d8a4b85cf3d581f5 languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.25.9" +"@babel/plugin-transform-modules-commonjs@npm:^7.24.7, @babel/plugin-transform-modules-commonjs@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" dependencies: - "@babel/helper-module-transforms": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-simple-access": ^7.25.9 + "@babel/helper-module-transforms": ^7.24.8 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-simple-access": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4f101f0ea4a57d1d27a7976d668c63a7d0bbb0d9c1909d8ac43c785fd1496c31e6552ffd9673730c088873df1bc64f1cc4aad7c3c90413ac5e80b33e336d80e4 + checksum: a4cf95b1639c33382064b44558f73ee5fac023f2a94d16e549d2bb55ceebd5cbc10fcddd505d08cd5bc97f5a64af9fd155512358b7dcf7b1a0082e8945cf21c5 languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.9" +"@babel/plugin-transform-modules-systemjs@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0" dependencies: - "@babel/helper-module-transforms": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-validator-identifier": ^7.25.9 - "@babel/traverse": ^7.25.9 + "@babel/helper-module-transforms": ^7.25.0 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-validator-identifier": ^7.24.7 + "@babel/traverse": ^7.25.0 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: bf446202f372ba92dc0db32b24b56225b6e3ad3b227e31074de8b86fdec01c273ae2536873e38dbe3ceb1cd0894209343adeaa37df208e3fa88c0c7dffec7924 + checksum: fe673bec08564e491847324bb80a1e6edfb229f5c37e58a094d51e95306e7b098e1d130fc43e992d22debd93b9beac74441ffc3f6ea5d78f6b2535896efa0728 languageName: node linkType: hard -"@babel/plugin-transform-modules-umd@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-modules-umd@npm:7.25.9" +"@babel/plugin-transform-modules-umd@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-umd@npm:7.24.7" dependencies: - "@babel/helper-module-transforms": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-module-transforms": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 946db66be5f04ab9ee56c424b00257276ec094aa2f148508927e6085239f76b00304fa1e33026d29eccdbe312efea15ca3d92e74a12689d7f0cdd9a7ba1a6c54 + checksum: 9ff1c464892efe042952ba778468bda6131b196a2729615bdcc3f24cdc94014f016a4616ee5643c5845bade6ba698f386833e61056d7201314b13a7fd69fac88 languageName: node linkType: hard -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.25.9" +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0 - checksum: 434346ba05cf74e3f4704b3bdd439287b95cd2a8676afcdc607810b8c38b6f4798cd69c1419726b2e4c7204e62e4a04d31b0360e91ca57a930521c9211e07789 + checksum: f1c6c7b5d60a86b6d7e4dd098798e1d393d55e993a0b57a73b53640c7a94985b601a96bdacee063f809a9a700bcea3a2ff18e98fa561554484ac56b761d774bd languageName: node linkType: hard -"@babel/plugin-transform-new-target@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-new-target@npm:7.25.9" +"@babel/plugin-transform-new-target@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-new-target@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f8113539919aafce52f07b2bd182c771a476fe1d5d96d813460b33a16f173f038929369c595572cadc1f7bd8cb816ce89439d056e007770ddd7b7a0878e7895f + checksum: 3cb94cd1076b270f768f91fdcf9dd2f6d487f8dbfff3df7ca8d07b915900b86d02769a35ba1407d16fe49499012c8f055e1741299e2c880798b953d942a8fa1b languageName: node linkType: hard -"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.25.9" +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 26e03b1c2c0408cc300e46d8f8cb639653ff3a7b03456d0d8afbb53c44f33a89323f51d99991dade3a5676921119bbdf869728bb7911799b5ef99ffafa2cdd24 + checksum: 4a9221356401d87762afbc37a9e8e764afc2daf09c421117537820f8cfbed6876888372ad3a7bcfae2d45c95f026651f050ab4020b777be31d3ffb00908dbdd3 languageName: node linkType: hard -"@babel/plugin-transform-numeric-separator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.25.9" +"@babel/plugin-transform-numeric-separator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0528ef041ed88e8c3f51624ee87b8182a7f246fe4013f0572788e0727d20795b558f2b82e3989b5dd416cbd339500f0d88857de41b6d3b6fdacb1d5344bcc5b1 + checksum: 561b5f1d08b2c3f92ce849f092751558b5e6cfeb7eb55c79e7375c34dd9c3066dce5e630bb439affef6adcf202b6cbcaaa23870070276fa5bb429c8f5b8c7514 languageName: node linkType: hard -"@babel/plugin-transform-object-rest-spread@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.25.9" +"@babel/plugin-transform-object-rest-spread@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.7" dependencies: - "@babel/helper-compilation-targets": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/plugin-transform-parameters": ^7.25.9 + "@babel/helper-compilation-targets": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-transform-parameters": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: a8ff73e1c46a03056b3a2236bafd6b3a4b83da93afe7ee24a50d0a8088150bf85bc5e5977daa04e66ff5fb7613d02d63ad49b91ebb64cf3f3022598d722e3a7a + checksum: 169d257b9800c13e1feb4c37fb05dae84f702e58b342bb76e19e82e6692b7b5337c9923ee89e3916a97c0dd04a3375bdeca14f5e126f110bbacbeb46d1886ca2 languageName: node linkType: hard -"@babel/plugin-transform-object-super@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-object-super@npm:7.25.9" +"@babel/plugin-transform-object-super@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-super@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-replace-supers": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-replace-supers": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1817b5d8b80e451ae1ad9080cca884f4f16df75880a158947df76a2ed8ab404d567a7dce71dd8051ef95f90fbe3513154086a32aba55cc76027f6cbabfbd7f98 + checksum: f71e607a830ee50a22fa1a2686524d3339440cf9dea63032f6efbd865cfe4e35000e1e3f3492459e5c986f7c0c07dc36938bf3ce61fc9ba5f8ab732d0b64ab37 languageName: node linkType: hard -"@babel/plugin-transform-optional-catch-binding@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.25.9" +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b46a8d1e91829f3db5c252583eb00d05a779b4660abeea5500fda0f8ffa3584fd18299443c22f7fddf0ed9dfdb73c782c43b445dc468d4f89803f2356963b406 + checksum: 7229f3a5a4facaab40f4fdfc7faabc157dc38a67d66bed7936599f4bc509e0bff636f847ac2aa45294881fce9cf8a0a460b85d2a465b7b977de9739fce9b18f6 languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.25.9" +"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f1642a7094456067e82b176e1e9fd426fda7ed9df54cb6d10109fc512b622bf4b3c83acc5875125732b8622565107fdbe2d60fe3ec8685e1d1c22c38c1b57782 + checksum: 45e55e3a2fffb89002d3f89aef59c141610f23b60eee41e047380bffc40290b59f64fc649aa7ec5281f73d41b2065410d788acc6afaad2a9f44cad6e8af04442 languageName: node linkType: hard -"@babel/plugin-transform-parameters@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-parameters@npm:7.25.9" +"@babel/plugin-transform-parameters@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-parameters@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d7ba2a7d05edbc85aed741289b0ff3d6289a1c25d82ac4be32c565f88a66391f46631aad59ceeed40824037f7eeaa7a0de1998db491f50e65a565cd964f78786 + checksum: ab534b03ac2eff94bc79342b8f39a4584666f5305a6c63c1964afda0b1b004e6b861e49d1683548030defe248e3590d3ff6338ee0552cb90c064f7e1479968c3 languageName: node linkType: hard -"@babel/plugin-transform-private-methods@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-private-methods@npm:7.25.9" +"@babel/plugin-transform-private-methods@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/plugin-transform-private-methods@npm:7.25.4" dependencies: - "@babel/helper-create-class-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-class-features-plugin": ^7.25.4 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6e3671b352c267847c53a170a1937210fa8151764d70d25005e711ef9b21969aaf422acc14f9f7fb86bc0e4ec43e7aefcc0ad9196ae02d262ec10f509f126a58 + checksum: cb1dabfc03e2977990263d65bc8f43a9037dffbb5d9a5f825c00d05447ff68015099408c1531d9dd88f18a41a90f5062dc48f3a1d52b415d2d2ee4827dedff09 languageName: node linkType: hard -"@babel/plugin-transform-private-property-in-object@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.25.9" +"@babel/plugin-transform-private-property-in-object@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.7" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-create-class-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.24.7 + "@babel/helper-create-class-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9ce3e983fea9b9ba677c192aa065c0b42ebdc7774be4c02135df09029ad92a55c35b004650c75952cb64d650872ed18f13ab64422c6fc891d06333762caa8a0a + checksum: 8cee9473095305cc787bb653fd681719b49363281feabf677db8a552e8e41c94441408055d7e5fd5c7d41b315e634fa70b145ad0c7c54456216049df4ed57350 languageName: node linkType: hard -"@babel/plugin-transform-property-literals@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-property-literals@npm:7.25.9" +"@babel/plugin-transform-property-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-property-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 436046ab07d54a9b44a384eeffec701d4e959a37a7547dda72e069e751ca7ff753d1782a8339e354b97c78a868b49ea97bf41bf5a44c6d7a3c0a05ad40eeb49c + checksum: 9aeefc3aab6c6bf9d1fae1cf3a2d38c7d886fd3c6c81b7c608c477f5758aee2e7abf52f32724310fe861da61af934ee2508b78a5b5f234b9740c9134e1c14437 languageName: node linkType: hard @@ -1073,300 +1265,302 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-display-name@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-react-display-name@npm:7.25.9" +"@babel/plugin-transform-react-display-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-display-name@npm:7.22.5" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: cd7020494e6f31c287834e8929e6a718d5b0ace21232fa30feb48622c2312045504c34b347dcff9e88145c349882b296a7d6b6cc3d3447d8c85502f16471747c + checksum: a12bfd1e4e93055efca3ace3c34722571bda59d9740dca364d225d9c6e3ca874f134694d21715c42cc63d79efd46db9665bd4a022998767f9245f1e29d5d204d languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-development@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-react-jsx-development@npm:7.25.9" +"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.22.5" dependencies: - "@babel/plugin-transform-react-jsx": ^7.25.9 + "@babel/plugin-transform-react-jsx": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 537d38369537f1eb56041c4b770bc0733fde1801a7f5ffef40a1217ea448f33ee2fa8e6098a58a82fd00e432c1b9426a66849496da419020c9eca3b1b1a23779 + checksum: 36bc3ff0b96bb0ef4723070a50cfdf2e72cfd903a59eba448f9fe92fea47574d6f22efd99364413719e1f3fb3c51b6c9b2990b87af088f8486a84b2a5f9e4560 languageName: node linkType: hard -"@babel/plugin-transform-react-jsx@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-react-jsx@npm:7.25.9" +"@babel/plugin-transform-react-jsx@npm:^7.22.15, @babel/plugin-transform-react-jsx@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/plugin-transform-react-jsx@npm:7.22.15" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-module-imports": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/plugin-syntax-jsx": ^7.25.9 - "@babel/types": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/plugin-syntax-jsx": ^7.22.5 + "@babel/types": ^7.22.15 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 5c6523c3963e3c6cf4c3cc2768a3766318af05b8f6c17aff52a4010e2c170e87b2fcdc94e9c9223ae12158664df4852ce81b9c8d042c15ea8fd83d6375f9f30f + checksum: 3899054e89550c3a0ef041af7c47ee266e2e934f498ee80fefeda778a6aa177b48aa8b4d2a8bf5848de977fec564571699ab952d9fa089c4c19b45ddb121df09 languageName: node linkType: hard -"@babel/plugin-transform-react-pure-annotations@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.25.9" +"@babel/plugin-transform-react-pure-annotations@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.22.5" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.22.5 + "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9995c0fc7c25d3aaaa0ce84233de02eab2564ea111d0813ec5baa538eb21520402879cc787ad1ad4c2061b99cebc3beb09910e64c9592e8ccb42ae62d9e4fd9a + checksum: 092021c4f404e267002099ec20b3f12dd730cb90b0d83c5feed3dc00dbe43b9c42c795a18e7c6c7d7bddea20c7dd56221b146aec81b37f2e7eb5137331c61120 languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-regenerator@npm:7.25.9" +"@babel/plugin-transform-regenerator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-regenerator@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 regenerator-transform: ^0.15.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 1c09e8087b476c5967282c9790fb8710e065eda77c60f6cb5da541edd59ded9d003d96f8ef640928faab4a0b35bf997673499a194973da4f0c97f0935807a482 + checksum: 20c6c3fb6fc9f407829087316653388d311e8c1816b007609bb09aeef254092a7157adace8b3aaa8f34be752503717cb85c88a5fe482180a9b11bcbd676063be languageName: node linkType: hard -"@babel/plugin-transform-regexp-modifiers@npm:^7.26.0": - version: 7.26.0 - resolution: "@babel/plugin-transform-regexp-modifiers@npm:7.26.0" +"@babel/plugin-transform-reserved-words@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-reserved-words@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 726deca486bbd4b176f8a966eb0f4aabc19d9def3b8dabb8b3a656778eca0df1fda3f3c92b213aa5a184232fdafd5b7bd73b4e24ca4345c498ef6baff2bda4e1 - languageName: node - linkType: hard - -"@babel/plugin-transform-reserved-words@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-reserved-words@npm:7.25.9" - dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 8beda04481b25767acbd1f6b9ef7b3a9c12fbd9dcb24df45a6ad120e1dc4b247c073db60ac742f9093657d6d8c050501fc0606af042f81a3bb6a3ff862cddc47 + checksum: 3d5876954d5914d7270819479504f30c4bf5452a65c677f44e2dab2db50b3c9d4b47793c45dfad7abf4f377035dd79e4b3f554ae350df9f422201d370ce9f8dd languageName: node linkType: hard -"@babel/plugin-transform-runtime@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-runtime@npm:7.25.9" +"@babel/plugin-transform-runtime@npm:^7.22.9": + version: 7.22.15 + resolution: "@babel/plugin-transform-runtime@npm:7.22.15" dependencies: - "@babel/helper-module-imports": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - babel-plugin-polyfill-corejs2: ^0.4.10 - babel-plugin-polyfill-corejs3: ^0.10.6 - babel-plugin-polyfill-regenerator: ^0.6.1 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-plugin-utils": ^7.22.5 + babel-plugin-polyfill-corejs2: ^0.4.5 + babel-plugin-polyfill-corejs3: ^0.8.3 + babel-plugin-polyfill-regenerator: ^0.5.2 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: db7f20a7a7324dbfe3b43a09f0095c69dadcf8b08567fa7c7fa6e245d97c66cdcdc330e97733b7589261c0e1046bc5cc36741b932ac5dd7757374495b57e7b02 + checksum: 7edf20b13d02f856276221624abf3b8084daa3f265a6e5c70ee0d0c63087fcf726dc8756a9c8bb3d25a1ce8697ab66ec8cdd15be992c21aed9971cb5bfe80a5b languageName: node linkType: hard -"@babel/plugin-transform-shorthand-properties@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.25.9" +"@babel/plugin-transform-shorthand-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f774995d58d4e3a992b732cf3a9b8823552d471040e280264dd15e0735433d51b468fef04d75853d061309389c66bda10ce1b298297ce83999220eb0ad62741d + checksum: 7b524245814607188212b8eb86d8c850e5974203328455a30881b4a92c364b93353fae14bc2af5b614ef16300b75b8c1d3b8f3a08355985b4794a7feb240adc3 languageName: node linkType: hard -"@babel/plugin-transform-spread@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-spread@npm:7.25.9" +"@babel/plugin-transform-spread@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-spread@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2403a5d49171b7714d5e5ecb1f598c61575a4dbe5e33e5a5f08c0ea990b75e693ca1ea983b6a96b2e3e5e7da48c8238333f525e47498c53b577c5d094d964c06 + checksum: 4c4254c8b9cceb1a8f975fa9b92257ddb08380a35c0a3721b8f4b9e13a3d82e403af2e0fba577b9f2452dd8f06bc3dea71cc53b1e2c6af595af5db52a13429d6 languageName: node linkType: hard -"@babel/plugin-transform-sticky-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.25.9" +"@babel/plugin-transform-sticky-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7454b00844dbe924030dd15e2b3615b36e196500c4c47e98dabc6b37a054c5b1038ecd437e910aabf0e43bf56b973cb148d3437d50f6e2332d8309568e3e979b + checksum: 118fc7a7ebf7c20411b670c8a030535fdfe4a88bc5643bb625a584dbc4c8a468da46430a20e6bf78914246962b0f18f1b9d6a62561a7762c4f34a038a5a77179 languageName: node linkType: hard -"@babel/plugin-transform-template-literals@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-template-literals@npm:7.25.9" +"@babel/plugin-transform-template-literals@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-template-literals@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 92eb1d6e2d95bd24abbb74fa7640d02b66ff6214e0bb616d7fda298a7821ce15132a4265d576a3502a347a3c9e94b6c69ed265bb0784664592fa076785a3d16a + checksum: ad44e5826f5a98c1575832dbdbd033adfe683cdff195e178528ead62507564bf02f479b282976cfd3caebad8b06d5fd7349c1cdb880dec3c56daea4f1f179619 languageName: node linkType: hard -"@babel/plugin-transform-typeof-symbol@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.25.9" +"@babel/plugin-transform-typeof-symbol@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3f9458840d96f61502f0e9dfaae3efe8325fa0b2151e24ea0d41307f28cdd166905419f5a43447ce0f1ae4bfd001f3906b658839a60269c254168164090b4c73 + checksum: 8663a8e7347cedf181001d99c88cf794b6598c3d82f324098510fe8fb8bd22113995526a77aa35a3cc5d70ffd0617a59dd0d10311a9bf0e1a3a7d3e59b900c00 languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-typescript@npm:7.25.9" +"@babel/plugin-transform-typescript@npm:^7.24.7": + version: 7.25.2 + resolution: "@babel/plugin-transform-typescript@npm:7.25.2" dependencies: - "@babel/helper-annotate-as-pure": ^7.25.9 - "@babel/helper-create-class-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 - "@babel/plugin-syntax-typescript": ^7.25.9 + "@babel/helper-annotate-as-pure": ^7.24.7 + "@babel/helper-create-class-features-plugin": ^7.25.0 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-skip-transparent-expression-wrappers": ^7.24.7 + "@babel/plugin-syntax-typescript": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6dd1303f1b9f314e22c6c54568a8b9709a081ce97be757d4004f960e3e73d6b819e6b49cee6cf1fc8455511e41127a8b580fa34602de62d17ab8a0b2d0ccf183 + checksum: b0267128d93560a4350919f7230a3b497e20fb8611d9f04bb3560d6b38877305ccad4c40903160263361c6930a84dbcb5b21b8ea923531bda51f67bffdc2dd0b languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.25.9" +"@babel/plugin-transform-unicode-escapes@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: be067e07488d804e3e82d7771f23666539d2ae5af03bf6eb8480406adf3dabd776e60c1fd5c6078dc5714b73cd80bbaca70e71d4f5d154c5c57200581602ca2f + checksum: 4af0a193e1ddea6ff82b2b15cc2501b872728050bd625740b813c8062fec917d32d530ff6b41de56c15e7296becdf3336a58db81f5ca8e7c445c1306c52f3e01 languageName: node linkType: hard -"@babel/plugin-transform-unicode-property-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.25.9" +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 201f6f46c1beb399e79aa208b94c5d54412047511795ce1e790edcd189cef73752e6a099fdfc01b3ad12205f139ae344143b62f21f44bbe02338a95e8506a911 + checksum: aae13350c50973f5802ca7906d022a6a0cc0e3aebac9122d0450bbd51e78252d4c2032ad69385e2759fcbdd3aac5d571bd7e26258907f51f8e1a51b53be626c2 languageName: node linkType: hard -"@babel/plugin-transform-unicode-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.25.9" +"@babel/plugin-transform-unicode-regex@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.7" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.24.7 + "@babel/helper-plugin-utils": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e8baae867526e179467c6ef5280d70390fa7388f8763a19a27c21302dd59b121032568be080749514b097097ceb9af716bf4b90638f1b3cf689aa837ba20150f + checksum: 1cb4e70678906e431da0a05ac3f8350025fee290304ad7482d9cfaa1ca67b2e898654de537c9268efbdad5b80d3ebadf42b4a88ea84609bd8a4cce7b11b48afd languageName: node linkType: hard -"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.9" +"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.4" dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-create-regexp-features-plugin": ^7.25.2 + "@babel/helper-plugin-utils": ^7.24.8 peerDependencies: "@babel/core": ^7.0.0 - checksum: 4445ef20de687cb4dcc95169742a8d9013d680aa5eee9186d8e25875bbfa7ee5e2de26a91177ccf70b1db518e36886abcd44750d28db5d7a9539f0efa6839f4b + checksum: 6d1a7e9fdde4ffc9a81c0e3f261b96a9a0dfe65da282ec96fe63b36c597a7389feac638f1df2a8a4f8c9128337bba8e984f934e9f19077930f33abf1926759ea languageName: node linkType: hard -"@babel/preset-env@npm:^7.20.2, @babel/preset-env@npm:^7.25.9": - version: 7.26.0 - resolution: "@babel/preset-env@npm:7.26.0" +"@babel/preset-env@npm:^7.20.2, @babel/preset-env@npm:^7.22.9": + version: 7.25.4 + resolution: "@babel/preset-env@npm:7.25.4" dependencies: - "@babel/compat-data": ^7.26.0 - "@babel/helper-compilation-targets": ^7.25.9 - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-validator-option": ^7.25.9 - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.25.9 - "@babel/plugin-bugfix-safari-class-field-initializer-scope": ^7.25.9 - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.25.9 - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.25.9 - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.25.9 + "@babel/compat-data": ^7.25.4 + "@babel/helper-compilation-targets": ^7.25.2 + "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-validator-option": ^7.24.8 + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.25.3 + "@babel/plugin-bugfix-safari-class-field-initializer-scope": ^7.25.0 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.25.0 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.24.7 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.25.0 "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 - "@babel/plugin-syntax-import-assertions": ^7.26.0 - "@babel/plugin-syntax-import-attributes": ^7.26.0 + "@babel/plugin-syntax-async-generators": ^7.8.4 + "@babel/plugin-syntax-class-properties": ^7.12.13 + "@babel/plugin-syntax-class-static-block": ^7.14.5 + "@babel/plugin-syntax-dynamic-import": ^7.8.3 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-import-assertions": ^7.24.7 + "@babel/plugin-syntax-import-attributes": ^7.24.7 + "@babel/plugin-syntax-import-meta": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.3 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 + "@babel/plugin-syntax-optional-chaining": ^7.8.3 + "@babel/plugin-syntax-private-property-in-object": ^7.14.5 + "@babel/plugin-syntax-top-level-await": ^7.14.5 "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 - "@babel/plugin-transform-arrow-functions": ^7.25.9 - "@babel/plugin-transform-async-generator-functions": ^7.25.9 - "@babel/plugin-transform-async-to-generator": ^7.25.9 - "@babel/plugin-transform-block-scoped-functions": ^7.25.9 - "@babel/plugin-transform-block-scoping": ^7.25.9 - "@babel/plugin-transform-class-properties": ^7.25.9 - "@babel/plugin-transform-class-static-block": ^7.26.0 - "@babel/plugin-transform-classes": ^7.25.9 - "@babel/plugin-transform-computed-properties": ^7.25.9 - "@babel/plugin-transform-destructuring": ^7.25.9 - "@babel/plugin-transform-dotall-regex": ^7.25.9 - "@babel/plugin-transform-duplicate-keys": ^7.25.9 - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ^7.25.9 - "@babel/plugin-transform-dynamic-import": ^7.25.9 - "@babel/plugin-transform-exponentiation-operator": ^7.25.9 - "@babel/plugin-transform-export-namespace-from": ^7.25.9 - "@babel/plugin-transform-for-of": ^7.25.9 - "@babel/plugin-transform-function-name": ^7.25.9 - "@babel/plugin-transform-json-strings": ^7.25.9 - "@babel/plugin-transform-literals": ^7.25.9 - "@babel/plugin-transform-logical-assignment-operators": ^7.25.9 - "@babel/plugin-transform-member-expression-literals": ^7.25.9 - "@babel/plugin-transform-modules-amd": ^7.25.9 - "@babel/plugin-transform-modules-commonjs": ^7.25.9 - "@babel/plugin-transform-modules-systemjs": ^7.25.9 - "@babel/plugin-transform-modules-umd": ^7.25.9 - "@babel/plugin-transform-named-capturing-groups-regex": ^7.25.9 - "@babel/plugin-transform-new-target": ^7.25.9 - "@babel/plugin-transform-nullish-coalescing-operator": ^7.25.9 - "@babel/plugin-transform-numeric-separator": ^7.25.9 - "@babel/plugin-transform-object-rest-spread": ^7.25.9 - "@babel/plugin-transform-object-super": ^7.25.9 - "@babel/plugin-transform-optional-catch-binding": ^7.25.9 - "@babel/plugin-transform-optional-chaining": ^7.25.9 - "@babel/plugin-transform-parameters": ^7.25.9 - "@babel/plugin-transform-private-methods": ^7.25.9 - "@babel/plugin-transform-private-property-in-object": ^7.25.9 - "@babel/plugin-transform-property-literals": ^7.25.9 - "@babel/plugin-transform-regenerator": ^7.25.9 - "@babel/plugin-transform-regexp-modifiers": ^7.26.0 - "@babel/plugin-transform-reserved-words": ^7.25.9 - "@babel/plugin-transform-shorthand-properties": ^7.25.9 - "@babel/plugin-transform-spread": ^7.25.9 - "@babel/plugin-transform-sticky-regex": ^7.25.9 - "@babel/plugin-transform-template-literals": ^7.25.9 - "@babel/plugin-transform-typeof-symbol": ^7.25.9 - "@babel/plugin-transform-unicode-escapes": ^7.25.9 - "@babel/plugin-transform-unicode-property-regex": ^7.25.9 - "@babel/plugin-transform-unicode-regex": ^7.25.9 - "@babel/plugin-transform-unicode-sets-regex": ^7.25.9 + "@babel/plugin-transform-arrow-functions": ^7.24.7 + "@babel/plugin-transform-async-generator-functions": ^7.25.4 + "@babel/plugin-transform-async-to-generator": ^7.24.7 + "@babel/plugin-transform-block-scoped-functions": ^7.24.7 + "@babel/plugin-transform-block-scoping": ^7.25.0 + "@babel/plugin-transform-class-properties": ^7.25.4 + "@babel/plugin-transform-class-static-block": ^7.24.7 + "@babel/plugin-transform-classes": ^7.25.4 + "@babel/plugin-transform-computed-properties": ^7.24.7 + "@babel/plugin-transform-destructuring": ^7.24.8 + "@babel/plugin-transform-dotall-regex": ^7.24.7 + "@babel/plugin-transform-duplicate-keys": ^7.24.7 + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ^7.25.0 + "@babel/plugin-transform-dynamic-import": ^7.24.7 + "@babel/plugin-transform-exponentiation-operator": ^7.24.7 + "@babel/plugin-transform-export-namespace-from": ^7.24.7 + "@babel/plugin-transform-for-of": ^7.24.7 + "@babel/plugin-transform-function-name": ^7.25.1 + "@babel/plugin-transform-json-strings": ^7.24.7 + "@babel/plugin-transform-literals": ^7.25.2 + "@babel/plugin-transform-logical-assignment-operators": ^7.24.7 + "@babel/plugin-transform-member-expression-literals": ^7.24.7 + "@babel/plugin-transform-modules-amd": ^7.24.7 + "@babel/plugin-transform-modules-commonjs": ^7.24.8 + "@babel/plugin-transform-modules-systemjs": ^7.25.0 + "@babel/plugin-transform-modules-umd": ^7.24.7 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.24.7 + "@babel/plugin-transform-new-target": ^7.24.7 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.24.7 + "@babel/plugin-transform-numeric-separator": ^7.24.7 + "@babel/plugin-transform-object-rest-spread": ^7.24.7 + "@babel/plugin-transform-object-super": ^7.24.7 + "@babel/plugin-transform-optional-catch-binding": ^7.24.7 + "@babel/plugin-transform-optional-chaining": ^7.24.8 + "@babel/plugin-transform-parameters": ^7.24.7 + "@babel/plugin-transform-private-methods": ^7.25.4 + "@babel/plugin-transform-private-property-in-object": ^7.24.7 + "@babel/plugin-transform-property-literals": ^7.24.7 + "@babel/plugin-transform-regenerator": ^7.24.7 + "@babel/plugin-transform-reserved-words": ^7.24.7 + "@babel/plugin-transform-shorthand-properties": ^7.24.7 + "@babel/plugin-transform-spread": ^7.24.7 + "@babel/plugin-transform-sticky-regex": ^7.24.7 + "@babel/plugin-transform-template-literals": ^7.24.7 + "@babel/plugin-transform-typeof-symbol": ^7.24.8 + "@babel/plugin-transform-unicode-escapes": ^7.24.7 + "@babel/plugin-transform-unicode-property-regex": ^7.24.7 + "@babel/plugin-transform-unicode-regex": ^7.24.7 + "@babel/plugin-transform-unicode-sets-regex": ^7.25.4 "@babel/preset-modules": 0.1.6-no-external-plugins babel-plugin-polyfill-corejs2: ^0.4.10 babel-plugin-polyfill-corejs3: ^0.10.6 babel-plugin-polyfill-regenerator: ^0.6.1 - core-js-compat: ^3.38.1 + core-js-compat: ^3.37.1 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 0c3e2b3758cc0347dcf5551b5209db702764183dce66ff20bffceff6486c090bef9175f5f7d1e68cfe5584f0d817b2aab25ab5992058a7998f061f244c8caf5f + checksum: 752be43f0b78a2eefe5007076aed3d21b505e1c09d134b61e7de8838f1bbb1e7af81023d39adb14b6eae23727fb5a9fd23f8115a44df043319be22319be17913 languageName: node linkType: hard @@ -1383,89 +1577,97 @@ __metadata: languageName: node linkType: hard -"@babel/preset-react@npm:^7.18.6, @babel/preset-react@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/preset-react@npm:7.25.9" +"@babel/preset-react@npm:^7.18.6, @babel/preset-react@npm:^7.22.5": + version: 7.22.15 + resolution: "@babel/preset-react@npm:7.22.15" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-validator-option": ^7.25.9 - "@babel/plugin-transform-react-display-name": ^7.25.9 - "@babel/plugin-transform-react-jsx": ^7.25.9 - "@babel/plugin-transform-react-jsx-development": ^7.25.9 - "@babel/plugin-transform-react-pure-annotations": ^7.25.9 + "@babel/helper-plugin-utils": ^7.22.5 + "@babel/helper-validator-option": ^7.22.15 + "@babel/plugin-transform-react-display-name": ^7.22.5 + "@babel/plugin-transform-react-jsx": ^7.22.15 + "@babel/plugin-transform-react-jsx-development": ^7.22.5 + "@babel/plugin-transform-react-pure-annotations": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b5650c07a744ab4024c04fae002c9043235b4ad8687de8bf759135b9c6186553f4f53fde0a4583ce4c019560b79c176f39c745cdf77645af07071d26d8ba84ce + checksum: c3ef99dfa2e9f57d2e08603e883aa20f47630a826c8e413888a93ae6e0084b5016871e463829be125329d40a1ba0a89f7c43d77b6dab52083c225cb43e63d10e languageName: node linkType: hard -"@babel/preset-typescript@npm:^7.21.0, @babel/preset-typescript@npm:^7.25.9": - version: 7.26.0 - resolution: "@babel/preset-typescript@npm:7.26.0" +"@babel/preset-typescript@npm:^7.21.0, @babel/preset-typescript@npm:^7.22.5": + version: 7.24.7 + resolution: "@babel/preset-typescript@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": ^7.25.9 - "@babel/helper-validator-option": ^7.25.9 - "@babel/plugin-syntax-jsx": ^7.25.9 - "@babel/plugin-transform-modules-commonjs": ^7.25.9 - "@babel/plugin-transform-typescript": ^7.25.9 + "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-validator-option": ^7.24.7 + "@babel/plugin-syntax-jsx": ^7.24.7 + "@babel/plugin-transform-modules-commonjs": ^7.24.7 + "@babel/plugin-transform-typescript": ^7.24.7 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6d8641fa6efd0e10eec5e8f92cd164b916a06d57131cfa5216c281404289c87d2b4995140a1c1d9c3bad171ff6ef2226be5f0585e09577ffff349706e991ec71 + checksum: 12929b24757f3bd6548103475f86478eda4c872bc7cefd920b29591eee8f4a4f350561d888e133d632d0c9402b8615fdcec9138e5127a6567dcb22f804ff207f languageName: node linkType: hard -"@babel/runtime-corejs3@npm:^7.25.9": - version: 7.26.0 - resolution: "@babel/runtime-corejs3@npm:7.26.0" +"@babel/regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "@babel/regjsgen@npm:0.8.0" + checksum: 89c338fee774770e5a487382170711014d49a68eb281e74f2b5eac88f38300a4ad545516a7786a8dd5702e9cf009c94c2f582d200f077ac5decd74c56b973730 + languageName: node + linkType: hard + +"@babel/runtime-corejs3@npm:^7.22.6": + version: 7.23.1 + resolution: "@babel/runtime-corejs3@npm:7.23.1" dependencies: core-js-pure: ^3.30.2 regenerator-runtime: ^0.14.0 - checksum: c6c5adac03e33aa4b5bb636a677aa2a6e400b91d91aac5674448d20af4100b80a8bedfb742338e4236e22c092d3edeb27210efdf48bd13ec353bd899f097ff41 + checksum: 5d52b0cc8b5d243e67cf29c584d15acdc0c89b64de4a3fe1cb8a83b84b64a5621802e36931f93ca696cb637884abd11c8514615d890a4edf057ec4464f73915d languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.25.9, @babel/runtime@npm:^7.8.4": - version: 7.26.0 - resolution: "@babel/runtime@npm:7.26.0" +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.8.4": + version: 7.23.1 + resolution: "@babel/runtime@npm:7.23.1" dependencies: regenerator-runtime: ^0.14.0 - checksum: c8e2c0504ab271b3467a261a8f119bf2603eb857a0d71e37791f4e3fae00f681365073cc79f141ddaa90c6077c60ba56448004ad5429d07ac73532be9f7cf28a + checksum: 0cd0d43e6e7dc7f9152fda8c8312b08321cda2f56ef53d6c22ebdd773abdc6f5d0a69008de90aa41908d00e2c1facb24715ff121274e689305c858355ff02c70 languageName: node linkType: hard -"@babel/template@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/template@npm:7.25.9" +"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/template@npm:7.25.0" dependencies: - "@babel/code-frame": ^7.25.9 - "@babel/parser": ^7.25.9 - "@babel/types": ^7.25.9 - checksum: 103641fea19c7f4e82dc913aa6b6ac157112a96d7c724d513288f538b84bae04fb87b1f1e495ac1736367b1bc30e10f058b30208fb25f66038e1f1eb4e426472 + "@babel/code-frame": ^7.24.7 + "@babel/parser": ^7.25.0 + "@babel/types": ^7.25.0 + checksum: 3f2db568718756d0daf2a16927b78f00c425046b654cd30b450006f2e84bdccaf0cbe6dc04994aa1f5f6a4398da2f11f3640a4d3ee31722e43539c4c919c817b languageName: node linkType: hard -"@babel/traverse@npm:^7.25.9": - version: 7.25.9 - resolution: "@babel/traverse@npm:7.25.9" +"@babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.3, @babel/traverse@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/traverse@npm:7.25.4" dependencies: - "@babel/code-frame": ^7.25.9 - "@babel/generator": ^7.25.9 - "@babel/parser": ^7.25.9 - "@babel/template": ^7.25.9 - "@babel/types": ^7.25.9 + "@babel/code-frame": ^7.24.7 + "@babel/generator": ^7.25.4 + "@babel/parser": ^7.25.4 + "@babel/template": ^7.25.0 + "@babel/types": ^7.25.4 debug: ^4.3.1 globals: ^11.1.0 - checksum: 901d325662ff1dd9bc51de00862e01055fa6bc374f5297d7e3731f2f0e268bbb1d2141f53fa82860aa308ee44afdcf186a948f16c83153927925804b95a9594d + checksum: 3b6d879b9d843b119501585269b3599f047011ae21eb7820d00aef62fc3a2bcdaf6f4cdf2679795a2d7c0b6b5d218974916e422f08dea08613dc42188ef21e4b languageName: node linkType: hard -"@babel/types@npm:^7.21.3, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.4.4": - version: 7.26.0 - resolution: "@babel/types@npm:7.26.0" +"@babel/types@npm:^7.21.3, @babel/types@npm:^7.22.15, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.4, @babel/types@npm:^7.4.4": + version: 7.25.4 + resolution: "@babel/types@npm:7.25.4" dependencies: - "@babel/helper-string-parser": ^7.25.9 - "@babel/helper-validator-identifier": ^7.25.9 - checksum: a3dd37dabac693018872da96edb8c1843a605c1bfacde6c3f504fba79b972426a6f24df70aa646356c0c1b19bdd2c722c623c684a996c002381071680602280d + "@babel/helper-string-parser": ^7.24.8 + "@babel/helper-validator-identifier": ^7.24.7 + to-fast-properties: ^2.0.0 + checksum: 497f8b583c54a92a59c3ec542144695064cd5c384fcca46ba1aa301d5e5dd6c1d011f312ca024cb0f9c956da07ae82fb4c348c31a30afa31a074c027720d2aa8 languageName: node linkType: hard @@ -1516,96 +1718,57 @@ __metadata: languageName: node linkType: hard -"@docusaurus/babel@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/babel@npm:3.6.0" +"@docusaurus/core@npm:3.5.2, @docusaurus/core@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/core@npm:3.5.2" dependencies: - "@babel/core": ^7.25.9 - "@babel/generator": ^7.25.9 + "@babel/core": ^7.23.3 + "@babel/generator": ^7.23.3 "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-transform-runtime": ^7.25.9 - "@babel/preset-env": ^7.25.9 - "@babel/preset-react": ^7.25.9 - "@babel/preset-typescript": ^7.25.9 - "@babel/runtime": ^7.25.9 - "@babel/runtime-corejs3": ^7.25.9 - "@babel/traverse": ^7.25.9 - "@docusaurus/logger": 3.6.0 - "@docusaurus/utils": 3.6.0 - babel-plugin-dynamic-import-node: ^2.3.3 - fs-extra: ^11.1.1 - tslib: ^2.6.0 - checksum: 4e1d8ff4b065508d26cd62a3f95fd94d00c450d41cef568d65696aee764e95e7f7d3e4849b441315fde18a1be5d891a28eef93c770910723a9f003eddeb0449c - languageName: node - linkType: hard - -"@docusaurus/bundler@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/bundler@npm:3.6.0" - dependencies: - "@babel/core": ^7.25.9 - "@docusaurus/babel": 3.6.0 - "@docusaurus/cssnano-preset": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 + "@babel/plugin-transform-runtime": ^7.22.9 + "@babel/preset-env": ^7.22.9 + "@babel/preset-react": ^7.22.5 + "@babel/preset-typescript": ^7.22.5 + "@babel/runtime": ^7.22.6 + "@babel/runtime-corejs3": ^7.22.6 + "@babel/traverse": ^7.22.8 + "@docusaurus/cssnano-preset": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 autoprefixer: ^10.4.14 - babel-loader: ^9.2.1 - clean-css: ^5.3.2 - copy-webpack-plugin: ^11.0.0 - css-loader: ^6.8.1 - css-minimizer-webpack-plugin: ^5.0.1 - cssnano: ^6.1.2 - file-loader: ^6.2.0 - html-minifier-terser: ^7.2.0 - mini-css-extract-plugin: ^2.9.1 - null-loader: ^4.0.1 - postcss: ^8.4.26 - postcss-loader: ^7.3.3 - react-dev-utils: ^12.0.1 - terser-webpack-plugin: ^5.3.9 - tslib: ^2.6.0 - url-loader: ^4.1.1 - webpack: ^5.95.0 - webpackbar: ^6.0.1 - peerDependencies: - "@docusaurus/faster": 3.5.2 - peerDependenciesMeta: - "@docusaurus/faster": - optional: true - checksum: 410d1ea38b3f788f17ac07c6e6ecfae7c47d235a467d9ebf7111e5945f574b12f61ce25d59c2197d7143ce7f8f4fb388d52ec4cd25b0ff23bece0a6ad6fad840 - languageName: node - linkType: hard - -"@docusaurus/core@npm:3.6.0, @docusaurus/core@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/core@npm:3.6.0" - dependencies: - "@docusaurus/babel": 3.6.0 - "@docusaurus/bundler": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + babel-loader: ^9.1.3 + babel-plugin-dynamic-import-node: ^2.3.3 boxen: ^6.2.1 chalk: ^4.1.2 chokidar: ^3.5.3 + clean-css: ^5.3.2 cli-table3: ^0.6.3 combine-promises: ^1.1.0 commander: ^5.1.0 + copy-webpack-plugin: ^11.0.0 core-js: ^3.31.1 + css-loader: ^6.8.1 + css-minimizer-webpack-plugin: ^5.0.1 + cssnano: ^6.1.2 del: ^6.1.1 detect-port: ^1.5.1 escape-html: ^1.0.3 eta: ^2.2.0 eval: ^0.1.8 + file-loader: ^6.2.0 fs-extra: ^11.1.1 + html-minifier-terser: ^7.2.0 html-tags: ^3.3.1 - html-webpack-plugin: ^5.6.0 + html-webpack-plugin: ^5.5.3 leven: ^3.1.0 lodash: ^4.17.21 + mini-css-extract-plugin: ^2.7.6 p-map: ^4.0.0 + postcss: ^8.4.26 + postcss-loader: ^7.3.3 prompts: ^2.4.2 react-dev-utils: ^12.0.1 react-helmet-async: ^1.3.0 @@ -1616,71 +1779,56 @@ __metadata: react-router-dom: ^5.3.4 rtl-detect: ^1.0.4 semver: ^7.5.4 - serve-handler: ^6.1.6 + serve-handler: ^6.1.5 shelljs: ^0.8.5 + terser-webpack-plugin: ^5.3.9 tslib: ^2.6.0 update-notifier: ^6.0.2 - webpack: ^5.95.0 - webpack-bundle-analyzer: ^4.10.2 - webpack-dev-server: ^4.15.2 - webpack-merge: ^6.0.1 + url-loader: ^4.1.1 + webpack: ^5.88.1 + webpack-bundle-analyzer: ^4.9.0 + webpack-dev-server: ^4.15.1 + webpack-merge: ^5.9.0 + webpackbar: ^5.0.2 peerDependencies: "@mdx-js/react": ^3.0.0 react: ^18.0.0 react-dom: ^18.0.0 bin: docusaurus: bin/docusaurus.mjs - checksum: cbf28e5c3d710c8e24da2e434347417789bea058aab56efa6b33e43555b84ab168eaf79f947c86edf3e417fa3e2607212c8585559d1fa099f19fc018d437a912 + checksum: 6c6282a75931f0f8f8f8768232b4436ff8679ae12b619f7bd01e0d83aa346e24ab0d9cecac034f9dc95c55059997efdd963d052d3e429583bfb8d3b54ab750d3 languageName: node linkType: hard -"@docusaurus/cssnano-preset@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/cssnano-preset@npm:3.6.0" +"@docusaurus/cssnano-preset@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/cssnano-preset@npm:3.5.2" dependencies: cssnano-preset-advanced: ^6.1.2 postcss: ^8.4.38 postcss-sort-media-queries: ^5.2.0 tslib: ^2.6.0 - checksum: 957c646df1b8593292d667e1b5e4abdce8d3bef484050885a88533560dffb778dafbb355c1a7fc30c4fe0f2be0321c518eb00e982db10ca1db067692c523f1be + checksum: 4bb1fae3741e14cbbdb64c1b0707435970838bf219831234a70cf382e6811ffac1cadf733d5e1fe7c278e7b2a9e533bfa802a5212b22ec46edd703208cf49f92 languageName: node linkType: hard -"@docusaurus/faster@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/faster@npm:3.6.0" - dependencies: - "@rspack/core": ^1.0.14 - "@swc/core": ^1.7.39 - "@swc/html": ^1.7.39 - browserslist: ^4.24.2 - lightningcss: ^1.27.0 - swc-loader: ^0.2.6 - tslib: ^2.6.0 - webpack: ^5.95.0 - peerDependencies: - "@docusaurus/types": "*" - checksum: eedf4ba04f43b2cc8e10d9f3b1b6c6254cafad64d76456361adfe7c14641a6d43fb24c41fe853b59e5bfe55131807d95f05b6e17e575958bdc6575f1e0d794a5 - languageName: node - linkType: hard - -"@docusaurus/logger@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/logger@npm:3.6.0" +"@docusaurus/logger@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/logger@npm:3.5.2" dependencies: chalk: ^4.1.2 tslib: ^2.6.0 - checksum: 36a02ac7d5c7f2140405c7adb032081dadb827fdb2ab45cf9fde938a37a2f47eded0564efb1c40b0ac16e58bb7300a9193c4bcdd2037cd495f4cc05c653192be + checksum: 7cbdcf54acd6e7787ca5a10b9c884be4b9e8fdae837862c66550a0bf3d02737f72c3188b2bddd61da6d8530eb2eb2b646ea599a79416e33c4998f1a87d2f6a8c languageName: node linkType: hard -"@docusaurus/mdx-loader@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/mdx-loader@npm:3.6.0" +"@docusaurus/mdx-loader@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/mdx-loader@npm:3.5.2" dependencies: - "@docusaurus/logger": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/logger": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 "@mdx-js/mdx": ^3.0.0 "@slorber/remark-comment": ^1.0.0 escape-html: ^1.0.3 @@ -1705,15 +1853,15 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: f44c1c650e30f53cc514662aa7dac9c3fc1781dac271faf38e31ac528330f4650e4e7547b592a34680e26c284d171ab8feed5571d2506f9f6392ebbbdfbb8ba2 + checksum: 36186c2f3487631757b24ba3a21575d2253ca1e6ada82d556bf323da7ae7637c0880eb388bf375e207bc5f26dcd8b58cc76d763e6c2caf6ed80f88748444ce8d languageName: node linkType: hard -"@docusaurus/module-type-aliases@npm:3.6.0, @docusaurus/module-type-aliases@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/module-type-aliases@npm:3.6.0" +"@docusaurus/module-type-aliases@npm:3.5.2, @docusaurus/module-type-aliases@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/module-type-aliases@npm:3.5.2" dependencies: - "@docusaurus/types": 3.6.0 + "@docusaurus/types": 3.5.2 "@types/history": ^4.7.11 "@types/react": "*" "@types/react-router-config": "*" @@ -1723,19 +1871,19 @@ __metadata: peerDependencies: react: "*" react-dom: "*" - checksum: 58e086a4e45f61c3b17faf98c6e5e8f42a97c56c15010f7dac84e72d6bbc3a8094349ce473cf906bbc56a532b32882e90e5f980584d31deb2d25780798c48a42 + checksum: 0161db859d459bb25ac162f0c509fb1316dfb403a9e89f325a9bc7d9f35ae1825b9703a435777903ba93de827d4413b189bbd0c03018ac13d66b50633302ea80 languageName: node linkType: hard -"@docusaurus/plugin-client-redirects@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-client-redirects@npm:3.6.0" +"@docusaurus/plugin-client-redirects@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/plugin-client-redirects@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 eta: ^2.2.0 fs-extra: ^11.1.1 lodash: ^4.17.21 @@ -1743,22 +1891,22 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: e5534884249b9b614d4579e1016988998c4fb1a3b884af223fecc2ffac225e7a5d90db331b0bc0f90b5e6dbeeb9fa1dd911c8ec36dd7486a512be6bcb04c30ab + checksum: 040aa829e819a43cb8d30f6c776c27a303080a4cb2fc2c398266fe9ecbd006dc53c6dd862ebcf4f74d0547042c4df6c4bbf080b3702be6df18c95b95c3e38f1d languageName: node linkType: hard -"@docusaurus/plugin-content-blog@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-content-blog@npm:3.6.0" +"@docusaurus/plugin-content-blog@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-content-blog@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/theme-common": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/theme-common": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 cheerio: 1.0.0-rc.12 feed: ^4.2.2 fs-extra: ^11.1.1 @@ -1773,23 +1921,23 @@ __metadata: "@docusaurus/plugin-content-docs": "*" react: ^18.0.0 react-dom: ^18.0.0 - checksum: 50581141a6610dc72a0cc8752efa8b1672157e5c604abd37da25a8bfdab4b3136f886cd61004a076315e65e75b11c53b12c84bdb50f2a6734c22845e35ff3551 + checksum: c5997b9d86ccf939998f9d56e65491ecf9e677d8425e95a79b3b428041d4dfc4ecb03a18ef595777c3ad5bd65f4a2dd30d99cb6f1b411161bf7cd32027ecc6d5 languageName: node linkType: hard -"@docusaurus/plugin-content-docs@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-content-docs@npm:3.6.0" +"@docusaurus/plugin-content-docs@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-content-docs@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/module-type-aliases": 3.6.0 - "@docusaurus/theme-common": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/module-type-aliases": 3.5.2 + "@docusaurus/theme-common": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 "@types/react-router-config": ^5.0.7 combine-promises: ^1.1.0 fs-extra: ^11.1.1 @@ -1801,157 +1949,156 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 47264764fbea004f539e57b31171a3d6802dd8481601d3ace9a82db4f43083cb428c1a7a235227b14b84e0be49b02169599b70ac83be928a428da2871e31d501 + checksum: fb7ba7f8a6741b14bbe8db0bf1b12ff7a24d12c40d8276f32b9b393881d74bfed3bed4f1e5b0756cac0e43c4bd8106094d5cf6a3c527400e9713283fc3832dab languageName: node linkType: hard -"@docusaurus/plugin-content-pages@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-content-pages@npm:3.6.0" +"@docusaurus/plugin-content-pages@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-content-pages@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 fs-extra: ^11.1.1 tslib: ^2.6.0 webpack: ^5.88.1 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 26d889fa3155b171ab878902b1da9fc675ee5ff816027ec43853ac4daeacb02fd55abaf503e5d6019cf7e25ba718a0efccb8dd91e970f4d880323b8151246a75 + checksum: 8b3f1040e8ec006c9431508e73ef3f61cd5759bece3770189f7d52609f91bd156c9b18d0608f9cb14c456a1d1823be6633c573d5eee7cf9bd142b0f978c7a745 languageName: node linkType: hard -"@docusaurus/plugin-debug@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-debug@npm:3.6.0" +"@docusaurus/plugin-debug@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-debug@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 fs-extra: ^11.1.1 react-json-view-lite: ^1.2.0 tslib: ^2.6.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: d0bb5a7fbf1594d540512a5e9b0f588dc1d4d5190b98f93a861437126ccf2a274e09d6aa4080906637a8401c85f8c2d018bd00fa2707f3d7d307e5769b2f5fba + checksum: a839e6c3a595ea202fdd7fbce638ab8df26ba73a8c7ead8c04d1bbb509ebe34e9633e7fe9eb54a7a733e93a03d74a60df4d9f6597b9621ff464280d4dd71db34 languageName: node linkType: hard -"@docusaurus/plugin-google-analytics@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-google-analytics@npm:3.6.0" +"@docusaurus/plugin-google-analytics@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-google-analytics@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 tslib: ^2.6.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: aa9c96099723be7454d6209973ebe14265c6e35c99d8231568c5c5ee47fc6c6ab11c826522ce0356fd52012acb11eae00df520ddb41504d8b02a0031f28b98f0 + checksum: 0b8c4d21333d40c2509d6ef807caaf69f085010c5deac514ab34f53b5486fd76766c90213dc98976a6c4d66fdfa14bf6b05594e51e8a53ec60c2a3fa08fd9a83 languageName: node linkType: hard -"@docusaurus/plugin-google-gtag@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-google-gtag@npm:3.6.0" +"@docusaurus/plugin-google-gtag@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-google-gtag@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 "@types/gtag.js": ^0.0.12 tslib: ^2.6.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 300bdc62ab115caef46498cc9c376ef4c79e48c1c0cc1f31c0c22ba54823801e1143d6e7447103815333bf47eacb3bf34baa1d3e809645ec233f3e743e8f2b1f + checksum: 5d53c2483c8c7e3a8e842bd091a774d4041f0e165d216b3c02f031a224a77258c9456e8b2acd0500b4a0eff474a83c1b82803628db9d4b132514409936c68ac4 languageName: node linkType: hard -"@docusaurus/plugin-google-tag-manager@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-google-tag-manager@npm:3.6.0" +"@docusaurus/plugin-google-tag-manager@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-google-tag-manager@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 tslib: ^2.6.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 37546382bf6edf17490b4d7a416e7c00cf3f09c591a402ba3d5519fe3c97bbfe54bc039964d0878677570fca82105b4e44ca8c80c29d6e43d94342568bdb865d + checksum: 9a6fc2ca54ea677c6edfd78f4f392d7d9ae86afd085fcda96d5ac41efa441352c25a2519595d9d15fb9b838e2ae39837f0daf02e2406c5cd56199ae237bd7b7a languageName: node linkType: hard -"@docusaurus/plugin-sitemap@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/plugin-sitemap@npm:3.6.0" +"@docusaurus/plugin-sitemap@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/plugin-sitemap@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 fs-extra: ^11.1.1 sitemap: ^7.1.1 tslib: ^2.6.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 7ece4a146f0b8fe663004f57bddd4568829e261d616ddafb3c83408121d881cc482d751cf88084ef43aed9103f8bb09602472f5b349b880f83c0101a4b123ce2 + checksum: 26b6bceb7ab87fe7f6f666742d1e81de32cdacc5aaa3d45d91002c7d64e3258f3d0aac87c6b0d442eaf34ede2af4b7521b50737f2e8e2718daff6fce10230213 languageName: node linkType: hard -"@docusaurus/preset-classic@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/preset-classic@npm:3.6.0" +"@docusaurus/preset-classic@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/preset-classic@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/plugin-content-blog": 3.6.0 - "@docusaurus/plugin-content-docs": 3.6.0 - "@docusaurus/plugin-content-pages": 3.6.0 - "@docusaurus/plugin-debug": 3.6.0 - "@docusaurus/plugin-google-analytics": 3.6.0 - "@docusaurus/plugin-google-gtag": 3.6.0 - "@docusaurus/plugin-google-tag-manager": 3.6.0 - "@docusaurus/plugin-sitemap": 3.6.0 - "@docusaurus/theme-classic": 3.6.0 - "@docusaurus/theme-common": 3.6.0 - "@docusaurus/theme-search-algolia": 3.6.0 - "@docusaurus/types": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/plugin-content-blog": 3.5.2 + "@docusaurus/plugin-content-docs": 3.5.2 + "@docusaurus/plugin-content-pages": 3.5.2 + "@docusaurus/plugin-debug": 3.5.2 + "@docusaurus/plugin-google-analytics": 3.5.2 + "@docusaurus/plugin-google-gtag": 3.5.2 + "@docusaurus/plugin-google-tag-manager": 3.5.2 + "@docusaurus/plugin-sitemap": 3.5.2 + "@docusaurus/theme-classic": 3.5.2 + "@docusaurus/theme-common": 3.5.2 + "@docusaurus/theme-search-algolia": 3.5.2 + "@docusaurus/types": 3.5.2 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: f32c335c2cec0f3a906aa8cb3fa97e6c1c5a2998a1926cc0b17f3de8ab5f1ad67bd938cce4d1884a32b46fa4f0191568b84511685c546bb3752ceef5be42142a + checksum: ec578e62b3b13b1874b14235a448a913c2d2358ea9b9d9c60bb250be468ab62387c88ec44e1ee82ad5b3d7243306e31919888a80eae62e5e8eab0ae12194bf69 languageName: node linkType: hard -"@docusaurus/theme-classic@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/theme-classic@npm:3.6.0" +"@docusaurus/theme-classic@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/theme-classic@npm:3.5.2" dependencies: - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/module-type-aliases": 3.6.0 - "@docusaurus/plugin-content-blog": 3.6.0 - "@docusaurus/plugin-content-docs": 3.6.0 - "@docusaurus/plugin-content-pages": 3.6.0 - "@docusaurus/theme-common": 3.6.0 - "@docusaurus/theme-translations": 3.6.0 - "@docusaurus/types": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/module-type-aliases": 3.5.2 + "@docusaurus/plugin-content-blog": 3.5.2 + "@docusaurus/plugin-content-docs": 3.5.2 + "@docusaurus/plugin-content-pages": 3.5.2 + "@docusaurus/theme-common": 3.5.2 + "@docusaurus/theme-translations": 3.5.2 + "@docusaurus/types": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 "@mdx-js/react": ^3.0.0 clsx: ^2.0.0 copy-text-to-clipboard: ^3.2.0 - infima: 0.2.0-alpha.45 + infima: 0.2.0-alpha.44 lodash: ^4.17.21 nprogress: ^0.2.0 postcss: ^8.4.26 @@ -1964,18 +2111,18 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: d44c7a5c44608dff740e5a81f51c589c7be2784565d69e63a1592225af9317f7282fd853d198187b9971f19fe5006973e733e2697cfd3121350aba982fe20ed1 + checksum: 6c415b01ad24bb43eb166e2b780a84356ff14a627627f6a541c2803832d56c4f9409a5636048693d2d24804f59c2cc7bda925d9ef999a8276fe125477d2b2e1e languageName: node linkType: hard -"@docusaurus/theme-common@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/theme-common@npm:3.6.0" +"@docusaurus/theme-common@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/theme-common@npm:3.5.2" dependencies: - "@docusaurus/mdx-loader": 3.6.0 - "@docusaurus/module-type-aliases": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 + "@docusaurus/mdx-loader": 3.5.2 + "@docusaurus/module-type-aliases": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 "@types/history": ^4.7.11 "@types/react": "*" "@types/react-router-config": "*" @@ -1988,22 +2135,22 @@ __metadata: "@docusaurus/plugin-content-docs": "*" react: ^18.0.0 react-dom: ^18.0.0 - checksum: f65410f3b959d0fed7a91883c99bab1637cd5ff7b05df2e957ee01feca0d52f21e623a58d17950fc78380bcbeb04140cd230876a1a240723c13ec205cae5e608 + checksum: c78ec7f6035abc920a2a0bc1ad78920178a5452538a3a70794eca8d4b976725f6ccc464ee3092afd31ca59b4e061ad4c21cdce7f5e10b06567075814b2fc2002 languageName: node linkType: hard -"@docusaurus/theme-search-algolia@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/theme-search-algolia@npm:3.6.0" +"@docusaurus/theme-search-algolia@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/theme-search-algolia@npm:3.5.2" dependencies: "@docsearch/react": ^3.5.2 - "@docusaurus/core": 3.6.0 - "@docusaurus/logger": 3.6.0 - "@docusaurus/plugin-content-docs": 3.6.0 - "@docusaurus/theme-common": 3.6.0 - "@docusaurus/theme-translations": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-validation": 3.6.0 + "@docusaurus/core": 3.5.2 + "@docusaurus/logger": 3.5.2 + "@docusaurus/plugin-content-docs": 3.5.2 + "@docusaurus/theme-common": 3.5.2 + "@docusaurus/theme-translations": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-validation": 3.5.2 algoliasearch: ^4.18.0 algoliasearch-helper: ^3.13.3 clsx: ^2.0.0 @@ -2015,30 +2162,30 @@ __metadata: peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 599f2cb0944fc955d5116270cd6ec3347df34a4e4285d0c90ca19e11802c880c53b27dd8687e0f6c35972578a623f1d9f5e0334e28740d027d627647bd5ca5a7 + checksum: e945e3001996477597bfad074eaef074cf4c5365ed3076c3109130a2252b266e4e2fac46904a0626eedeff23b9ac11e7b985cc71f5485ede52d3ddf379b7959b languageName: node linkType: hard -"@docusaurus/theme-translations@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/theme-translations@npm:3.6.0" +"@docusaurus/theme-translations@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/theme-translations@npm:3.5.2" dependencies: fs-extra: ^11.1.1 tslib: ^2.6.0 - checksum: 962c1366173bdf9f66e4a8a309fd70c7434caf1638cf1c6112ee05cf102d9ae719ec5edeec663bb90607749e98fa7e040362f2f512388cea44d255c519a3bcf0 + checksum: dc523c74a13fb8552c03e547c6de1c21881d899cc74bf088a2bed716e0ef1a4ceba2726c43656d87fff60413ca191f5ea946b182e4ae4129c14da832b5194d82 languageName: node linkType: hard -"@docusaurus/tsconfig@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/tsconfig@npm:3.6.0" - checksum: 98d32f16fb015b299518ba1f7fa76be8d2faf6788a076c35a89f4197f3b8ef57a8524f7bde14a140a4f03e4522c1edba00a79d3e4573536d4c9d101742baa586 +"@docusaurus/tsconfig@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/tsconfig@npm:3.5.2" + checksum: 808a17eaf422ae9a948c6558dd1e92d4700b067ead3a63a84049c6845bf94f84e311cd0e4d517047fe9ea057efe393bb22c2d5c92d727d06c9f895e971f2c3ea languageName: node linkType: hard -"@docusaurus/types@npm:3.6.0, @docusaurus/types@npm:^3.6.0": - version: 3.6.0 - resolution: "@docusaurus/types@npm:3.6.0" +"@docusaurus/types@npm:3.5.2, @docusaurus/types@npm:^3.1.1": + version: 3.5.2 + resolution: "@docusaurus/types@npm:3.5.2" dependencies: "@mdx-js/mdx": ^3.0.0 "@types/history": ^4.7.11 @@ -2047,18 +2194,18 @@ __metadata: joi: ^17.9.2 react-helmet-async: ^1.3.0 utility-types: ^3.10.0 - webpack: ^5.95.0 + webpack: ^5.88.1 webpack-merge: ^5.9.0 peerDependencies: react: ^18.0.0 react-dom: ^18.0.0 - checksum: 0599cc5311f96487230759f6186bba57f2ef5e7bd0a37d2d57d5a02c53c579e341ca1aca4c8075111352191f7dc25c9411533c34a344a42727dc88626b30d28c + checksum: e39451b7b08673ad5e1551ee6e4286f90f2554cf9ba245abfa56670550f48afca9c57b01c10ffa21dacb734c0fcd067150eeb2b1c1ebb1692f1f538b1eed0029 languageName: node linkType: hard -"@docusaurus/utils-common@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/utils-common@npm:3.6.0" +"@docusaurus/utils-common@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/utils-common@npm:3.5.2" dependencies: tslib: ^2.6.0 peerDependencies: @@ -2066,32 +2213,32 @@ __metadata: peerDependenciesMeta: "@docusaurus/types": optional: true - checksum: 473056b9a6e3fd7592698ca26cf4b4a4f2e1cbdf672b66c6d1cbeffd390e41081b8b44ccf93bb12ec279461a7163f37870b4b0d51630215d7f1f89865b7595a3 + checksum: 9d550c89663d4271456ae0832c82a1691207ccc95e21df3a05a4bd6bbd2624bb9e3ab7327d939c04b2023378987bcf99321b2c37be1af214852832f65d6db14a languageName: node linkType: hard -"@docusaurus/utils-validation@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/utils-validation@npm:3.6.0" +"@docusaurus/utils-validation@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/utils-validation@npm:3.5.2" dependencies: - "@docusaurus/logger": 3.6.0 - "@docusaurus/utils": 3.6.0 - "@docusaurus/utils-common": 3.6.0 + "@docusaurus/logger": 3.5.2 + "@docusaurus/utils": 3.5.2 + "@docusaurus/utils-common": 3.5.2 fs-extra: ^11.2.0 joi: ^17.9.2 js-yaml: ^4.1.0 lodash: ^4.17.21 tslib: ^2.6.0 - checksum: 8e340d8dc12809dbcf307a97c6e1307d1134600a2492b6028aa603b1b84e4b31e6444cee509372f44c98b3e838323baa5b2f3a34e41c0152ec72c7a2e543cd60 + checksum: 5966e6d0e8f26292c629899f13b545501b53b345b0e2291bb47aaa80d7c9c5cf155e15a4ecd073a4095ee7c83c6db3612e0a34f81a8187fd20410b1aeb92d731 languageName: node linkType: hard -"@docusaurus/utils@npm:3.6.0": - version: 3.6.0 - resolution: "@docusaurus/utils@npm:3.6.0" +"@docusaurus/utils@npm:3.5.2": + version: 3.5.2 + resolution: "@docusaurus/utils@npm:3.5.2" dependencies: - "@docusaurus/logger": 3.6.0 - "@docusaurus/utils-common": 3.6.0 + "@docusaurus/logger": 3.5.2 + "@docusaurus/utils-common": 3.5.2 "@svgr/webpack": ^8.1.0 escape-string-regexp: ^4.0.0 file-loader: ^6.2.0 @@ -2115,7 +2262,7 @@ __metadata: peerDependenciesMeta: "@docusaurus/types": optional: true - checksum: 054b8414eccdd08f1145521ea7c32895b4036a95613b8f88cdb608a4b9bebee9911be724537d620c084383644366529d6174515b20f4da89b66f2e9e90ac1679 + checksum: 0e0f4fc65ed076d4e4b551ecb61447b7c2468060d1655afff314515844ae34dc0546f467f53bff535f3144afc109e974da27fadb7c678a5d19966bed9e7a27c4 languageName: node linkType: hard @@ -2267,42 +2414,6 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-tools@npm:0.5.1": - version: 0.5.1 - resolution: "@module-federation/runtime-tools@npm:0.5.1" - dependencies: - "@module-federation/runtime": 0.5.1 - "@module-federation/webpack-bundler-runtime": 0.5.1 - checksum: 651051fb6e2e63915b408547b7d6bdea06338857e293e293b088e330dbb78e147df1b74c5e1f9d1e93ea6e61706f2d4511b8a0dc487703b5615db9695ee9e8ad - languageName: node - linkType: hard - -"@module-federation/runtime@npm:0.5.1": - version: 0.5.1 - resolution: "@module-federation/runtime@npm:0.5.1" - dependencies: - "@module-federation/sdk": 0.5.1 - checksum: 810e350dbd12a7f4bffb860375fd28a26a560669128f5339d729bc40810ae9b503b4034cbbb90e7105fd1df5544c3bc9cf11dfd2a47e2eaa2c50d00ad759b1e2 - languageName: node - linkType: hard - -"@module-federation/sdk@npm:0.5.1": - version: 0.5.1 - resolution: "@module-federation/sdk@npm:0.5.1" - checksum: 75f225926564779db3113aae9cd1b89d303b753026c84945a5225b496554db9e3a2fe2e1d594af4357708853337f161235f46ed5e6320592ac1e8b07756bf918 - languageName: node - linkType: hard - -"@module-federation/webpack-bundler-runtime@npm:0.5.1": - version: 0.5.1 - resolution: "@module-federation/webpack-bundler-runtime@npm:0.5.1" - dependencies: - "@module-federation/runtime": 0.5.1 - "@module-federation/sdk": 0.5.1 - checksum: a84a7b9482f133eba0fb8fd77ea87310a1028b7d5fc3da4a17b2bb5fc3fc9fc440cb32ed927f74e1bfe61925eec361512884d84b236b3cdab74276c0dcfff840 - languageName: node - linkType: hard - "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -2518,129 +2629,6 @@ __metadata: languageName: node linkType: hard -"@rspack/binding-darwin-arm64@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-darwin-arm64@npm:1.0.14" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@rspack/binding-darwin-x64@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-darwin-x64@npm:1.0.14" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@rspack/binding-linux-arm64-gnu@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-linux-arm64-gnu@npm:1.0.14" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@rspack/binding-linux-arm64-musl@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-linux-arm64-musl@npm:1.0.14" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@rspack/binding-linux-x64-gnu@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-linux-x64-gnu@npm:1.0.14" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@rspack/binding-linux-x64-musl@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-linux-x64-musl@npm:1.0.14" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@rspack/binding-win32-arm64-msvc@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-win32-arm64-msvc@npm:1.0.14" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@rspack/binding-win32-ia32-msvc@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-win32-ia32-msvc@npm:1.0.14" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@rspack/binding-win32-x64-msvc@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding-win32-x64-msvc@npm:1.0.14" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@rspack/binding@npm:1.0.14": - version: 1.0.14 - resolution: "@rspack/binding@npm:1.0.14" - dependencies: - "@rspack/binding-darwin-arm64": 1.0.14 - "@rspack/binding-darwin-x64": 1.0.14 - "@rspack/binding-linux-arm64-gnu": 1.0.14 - "@rspack/binding-linux-arm64-musl": 1.0.14 - "@rspack/binding-linux-x64-gnu": 1.0.14 - "@rspack/binding-linux-x64-musl": 1.0.14 - "@rspack/binding-win32-arm64-msvc": 1.0.14 - "@rspack/binding-win32-ia32-msvc": 1.0.14 - "@rspack/binding-win32-x64-msvc": 1.0.14 - dependenciesMeta: - "@rspack/binding-darwin-arm64": - optional: true - "@rspack/binding-darwin-x64": - optional: true - "@rspack/binding-linux-arm64-gnu": - optional: true - "@rspack/binding-linux-arm64-musl": - optional: true - "@rspack/binding-linux-x64-gnu": - optional: true - "@rspack/binding-linux-x64-musl": - optional: true - "@rspack/binding-win32-arm64-msvc": - optional: true - "@rspack/binding-win32-ia32-msvc": - optional: true - "@rspack/binding-win32-x64-msvc": - optional: true - checksum: 0fae05a49eb978cb565ebe78d66a51565fd833ee15b2e1f7739e98ccad706faacdd662c6f10a12d730004f62a8ec3a5e87521746ddc127b0c91116ba751504aa - languageName: node - linkType: hard - -"@rspack/core@npm:^1.0.14": - version: 1.0.14 - resolution: "@rspack/core@npm:1.0.14" - dependencies: - "@module-federation/runtime-tools": 0.5.1 - "@rspack/binding": 1.0.14 - "@rspack/lite-tapable": 1.0.1 - caniuse-lite: ^1.0.30001616 - peerDependencies: - "@swc/helpers": ">=0.5.1" - peerDependenciesMeta: - "@swc/helpers": - optional: true - checksum: 0aeb557b36ba03b0c8a51f5e46d4671c245fb6e3b47c26ecb5c9e0d18afece9c88266c3ff3a809345fc5f6dbdeb63747a2495397a153537531c5224de340c38e - languageName: node - linkType: hard - -"@rspack/lite-tapable@npm:1.0.1": - version: 1.0.1 - resolution: "@rspack/lite-tapable@npm:1.0.1" - checksum: a490aa7868178e7277573293a2b81191513d451c72f4118173f080b5c65a19618e1d37083cffa049b563433a3f772ab2f4424c0a920b04b1347ddb12fe3bcbf8 - languageName: node - linkType: hard - "@sideway/address@npm:^4.1.3": version: 4.1.4 resolution: "@sideway/address@npm:4.1.4" @@ -2696,15 +2684,6 @@ __metadata: languageName: node linkType: hard -"@spotify/prettier-config@npm:^15.0.0": - version: 15.0.0 - resolution: "@spotify/prettier-config@npm:15.0.0" - peerDependencies: - prettier: 2.x - checksum: aa5ec5739427f9acdb9d62ae6c04f04a344898567239f7ee45c75c6205ebdffbc61747ea8de6e83baf0bc3785359967de4b7097a8723c4b4063ff57dc5cb6c44 - languageName: node - linkType: hard - "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": version: 8.0.0 resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" @@ -2861,92 +2840,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-darwin-arm64@npm:1.9.2" +"@swc/core-darwin-arm64@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-darwin-arm64@npm:1.9.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-darwin-x64@npm:1.9.2" +"@swc/core-darwin-x64@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-darwin-x64@npm:1.9.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.9.2" +"@swc/core-linux-arm-gnueabihf@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.9.3" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm64-gnu@npm:1.9.2" +"@swc/core-linux-arm64-gnu@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm64-gnu@npm:1.9.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm64-musl@npm:1.9.2" +"@swc/core-linux-arm64-musl@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm64-musl@npm:1.9.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-x64-gnu@npm:1.9.2" +"@swc/core-linux-x64-gnu@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-x64-gnu@npm:1.9.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-x64-musl@npm:1.9.2" +"@swc/core-linux-x64-musl@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-x64-musl@npm:1.9.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-arm64-msvc@npm:1.9.2" +"@swc/core-win32-arm64-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-arm64-msvc@npm:1.9.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-ia32-msvc@npm:1.9.2" +"@swc/core-win32-ia32-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-ia32-msvc@npm:1.9.3" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-x64-msvc@npm:1.9.2" +"@swc/core-win32-x64-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-x64-msvc@npm:1.9.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.46, @swc/core@npm:^1.7.39": - version: 1.9.2 - resolution: "@swc/core@npm:1.9.2" +"@swc/core@npm:^1.3.46": + version: 1.9.3 + resolution: "@swc/core@npm:1.9.3" dependencies: - "@swc/core-darwin-arm64": 1.9.2 - "@swc/core-darwin-x64": 1.9.2 - "@swc/core-linux-arm-gnueabihf": 1.9.2 - "@swc/core-linux-arm64-gnu": 1.9.2 - "@swc/core-linux-arm64-musl": 1.9.2 - "@swc/core-linux-x64-gnu": 1.9.2 - "@swc/core-linux-x64-musl": 1.9.2 - "@swc/core-win32-arm64-msvc": 1.9.2 - "@swc/core-win32-ia32-msvc": 1.9.2 - "@swc/core-win32-x64-msvc": 1.9.2 + "@swc/core-darwin-arm64": 1.9.3 + "@swc/core-darwin-x64": 1.9.3 + "@swc/core-linux-arm-gnueabihf": 1.9.3 + "@swc/core-linux-arm64-gnu": 1.9.3 + "@swc/core-linux-arm64-musl": 1.9.3 + "@swc/core-linux-x64-gnu": 1.9.3 + "@swc/core-linux-x64-musl": 1.9.3 + "@swc/core-win32-arm64-msvc": 1.9.3 + "@swc/core-win32-ia32-msvc": 1.9.3 + "@swc/core-win32-x64-msvc": 1.9.3 "@swc/counter": ^0.1.3 - "@swc/types": ^0.1.15 + "@swc/types": ^0.1.17 peerDependencies: "@swc/helpers": "*" dependenciesMeta: @@ -2973,7 +2952,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 325afca1473e371804cc420d096553a0c6b19d01296b46b23e3b75a797c8b139c712ad79bc5c876cfc6d7bd6d60014a9f81286a2e888e94f0dec70903893f0b6 + checksum: 4d83aee0b4d9c543f247d680796e5b9cb69997369dcd81642c2603e185312dfb1674328a7ceb1d352c21275155a71789f76dafe8853055d076b6241d5760bbed languageName: node linkType: hard @@ -2984,122 +2963,12 @@ __metadata: languageName: node linkType: hard -"@swc/html-darwin-arm64@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-darwin-arm64@npm:1.8.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@swc/html-darwin-x64@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-darwin-x64@npm:1.8.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@swc/html-linux-arm-gnueabihf@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-linux-arm-gnueabihf@npm:1.8.0" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@swc/html-linux-arm64-gnu@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-linux-arm64-gnu@npm:1.8.0" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@swc/html-linux-arm64-musl@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-linux-arm64-musl@npm:1.8.0" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@swc/html-linux-x64-gnu@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-linux-x64-gnu@npm:1.8.0" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@swc/html-linux-x64-musl@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-linux-x64-musl@npm:1.8.0" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@swc/html-win32-arm64-msvc@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-win32-arm64-msvc@npm:1.8.0" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@swc/html-win32-ia32-msvc@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-win32-ia32-msvc@npm:1.8.0" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@swc/html-win32-x64-msvc@npm:1.8.0": - version: 1.8.0 - resolution: "@swc/html-win32-x64-msvc@npm:1.8.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@swc/html@npm:^1.7.39": - version: 1.8.0 - resolution: "@swc/html@npm:1.8.0" +"@swc/types@npm:^0.1.17": + version: 0.1.17 + resolution: "@swc/types@npm:0.1.17" dependencies: "@swc/counter": ^0.1.3 - "@swc/html-darwin-arm64": 1.8.0 - "@swc/html-darwin-x64": 1.8.0 - "@swc/html-linux-arm-gnueabihf": 1.8.0 - "@swc/html-linux-arm64-gnu": 1.8.0 - "@swc/html-linux-arm64-musl": 1.8.0 - "@swc/html-linux-x64-gnu": 1.8.0 - "@swc/html-linux-x64-musl": 1.8.0 - "@swc/html-win32-arm64-msvc": 1.8.0 - "@swc/html-win32-ia32-msvc": 1.8.0 - "@swc/html-win32-x64-msvc": 1.8.0 - dependenciesMeta: - "@swc/html-darwin-arm64": - optional: true - "@swc/html-darwin-x64": - optional: true - "@swc/html-linux-arm-gnueabihf": - optional: true - "@swc/html-linux-arm64-gnu": - optional: true - "@swc/html-linux-arm64-musl": - optional: true - "@swc/html-linux-x64-gnu": - optional: true - "@swc/html-linux-x64-musl": - optional: true - "@swc/html-win32-arm64-msvc": - optional: true - "@swc/html-win32-ia32-msvc": - optional: true - "@swc/html-win32-x64-msvc": - optional: true - checksum: c7d74549141a5ccd2bacee4eadeb380808a53f34214f9b31257b92418aabfec8852013c310a893963d8ab4c4fae6195f1ca97ba8b40c8f451f25f6b3704a7cc0 - languageName: node - linkType: hard - -"@swc/types@npm:^0.1.15": - version: 0.1.15 - resolution: "@swc/types@npm:0.1.15" - dependencies: - "@swc/counter": ^0.1.3 - checksum: 19889eed42d28f5dcef7c16f3b0cf4375890984b106aca46d9455d1f5ba364156d206a8e1f73962718ee408ff9e460b84aaa79025bf8dc30e0d6ded471e1e2d2 + checksum: 6cc87b8ddfb540096abdf40bc29742df0b7d068f97c1ce6c32cd1b7073cde263ed7bc3bae1fba7bf0e1a0f5d63336e9fa092e05a54f6d9b3570df956d2acaff6 languageName: node linkType: hard @@ -3182,26 +3051,6 @@ __metadata: languageName: node linkType: hard -"@types/eslint-scope@npm:^3.7.7": - version: 3.7.7 - resolution: "@types/eslint-scope@npm:3.7.7" - dependencies: - "@types/eslint": "*" - "@types/estree": "*" - checksum: e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e - languageName: node - linkType: hard - -"@types/eslint@npm:*": - version: 9.6.1 - resolution: "@types/eslint@npm:9.6.1" - dependencies: - "@types/estree": "*" - "@types/json-schema": "*" - checksum: c286e79707ab604b577cf8ce51d9bbb9780e3d6a68b38a83febe13fa05b8012c92de17c28532fac2b03d3c460123f5055d603a579685325246ca1c86828223e0 - languageName: node - linkType: hard - "@types/estree-jsx@npm:^1.0.0": version: 1.0.0 resolution: "@types/estree-jsx@npm:1.0.0" @@ -3211,7 +3060,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": version: 1.0.6 resolution: "@types/estree@npm:1.0.6" checksum: 8825d6e729e16445d9a1dd2fb1db2edc5ed400799064cd4d028150701031af012ba30d6d03fe9df40f4d7a437d0de6d2b256020152b7b09bde9f2e420afdffd9 @@ -3312,10 +3161,10 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 +"@types/json-schema@npm:^7.0.4, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": + version: 7.0.11 + resolution: "@types/json-schema@npm:7.0.11" + checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d languageName: node linkType: hard @@ -3734,6 +3583,15 @@ __metadata: languageName: node linkType: hard +"acorn-import-attributes@npm:^1.9.5": + version: 1.9.5 + resolution: "acorn-import-attributes@npm:1.9.5" + peerDependencies: + acorn: ^8 + checksum: 1c0c49b6a244503964ae46ae850baccf306e84caf99bc2010ed6103c69a423987b07b520a6c619f075d215388bd4923eccac995886a54309eda049ab78a4be95 + languageName: node + linkType: hard + "acorn-jsx@npm:^5.0.0": version: 5.3.2 resolution: "acorn-jsx@npm:5.3.2" @@ -3750,12 +3608,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.14.0, acorn@npm:^8.8.2": - version: 8.14.0 - resolution: "acorn@npm:8.14.0" +"acorn@npm:^8.0.0, acorn@npm:^8.0.4, acorn@npm:^8.7.1, acorn@npm:^8.8.2": + version: 8.10.0 + resolution: "acorn@npm:8.10.0" bin: acorn: bin/acorn - checksum: 8755074ba55fff94e84e81c72f1013c2d9c78e973c31231c8ae505a5f966859baf654bddd75046bffd73ce816b149298977fff5077a3033dedba0ae2aad152d4 + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d languageName: node linkType: hard @@ -3896,15 +3754,6 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:^4.3.2": - version: 4.3.2 - resolution: "ansi-escapes@npm:4.3.2" - dependencies: - type-fest: ^0.21.3 - checksum: 93111c42189c0a6bed9cdb4d7f2829548e943827ee8479c74d6e0b22ee127b2a21d3f8b5ca57723b8ef78ce011fbfc2784350eb2bde3ccfccf2f575fa8489815 - languageName: node - linkType: hard - "ansi-html-community@npm:^0.0.8": version: 0.0.8 resolution: "ansi-html-community@npm:0.0.8" @@ -3928,7 +3777,16 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": +"ansi-styles@npm:^3.2.1": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: ^1.9.0 + checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 + languageName: node + linkType: hard + +"ansi-styles@npm:^4.1.0": version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: @@ -4049,16 +3907,16 @@ __metadata: languageName: node linkType: hard -"babel-loader@npm:^9.2.1": - version: 9.2.1 - resolution: "babel-loader@npm:9.2.1" +"babel-loader@npm:^9.1.3": + version: 9.1.3 + resolution: "babel-loader@npm:9.1.3" dependencies: find-cache-dir: ^4.0.0 schema-utils: ^4.0.0 peerDependencies: "@babel/core": ^7.12.0 webpack: ">=5" - checksum: e1858d7625ad7cc8cabe6bbb8657f957041ffb1308375f359e92aa1654f413bfbb86a281bbf7cd4f7fff374d571c637b117551deac0231d779a198d4e4e78331 + checksum: b168dde5b8cf11206513371a79f86bb3faa7c714e6ec9fffd420876b61f3d7f5f4b976431095ef6a14bc4d324505126deb91045fd41e312ba49f4deaa166fe28 languageName: node linkType: hard @@ -4071,7 +3929,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.10": +"babel-plugin-polyfill-corejs2@npm:^0.4.10, babel-plugin-polyfill-corejs2@npm:^0.4.5": version: 0.4.11 resolution: "babel-plugin-polyfill-corejs2@npm:0.4.11" dependencies: @@ -4096,6 +3954,29 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs3@npm:^0.8.3": + version: 0.8.4 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.4" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.2 + core-js-compat: ^3.32.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 7243241a5b978b1335d51bcbd1248d6c4df88f6b3726706e71e0392f111c59bbf01118c85bb0ed42dce65e90e8fc768d19eda0a81a321cbe54abd3df9a285dc8 + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.5.2": + version: 0.5.2 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.2" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.4.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: d962200f604016a9a09bc9b4aaf60a3db7af876bb65bcefaeac04d44ac9d9ec4037cf24ce117760cc141d7046b6394c7eb0320ba9665cb4a2ee64df2be187c93 + languageName: node + linkType: hard + "babel-plugin-polyfill-regenerator@npm:^0.6.1": version: 0.6.2 resolution: "babel-plugin-polyfill-regenerator@npm:0.6.2" @@ -4111,15 +3992,13 @@ __metadata: version: 0.0.0-use.local resolution: "backstage-microsite@workspace:." dependencies: - "@docusaurus/core": ^3.6.0 - "@docusaurus/faster": ^3.6.0 - "@docusaurus/module-type-aliases": ^3.6.0 - "@docusaurus/plugin-client-redirects": ^3.6.0 - "@docusaurus/preset-classic": ^3.6.0 - "@docusaurus/tsconfig": ^3.6.0 - "@docusaurus/types": ^3.6.0 + "@docusaurus/core": ^3.1.1 + "@docusaurus/module-type-aliases": ^3.1.1 + "@docusaurus/plugin-client-redirects": ^3.1.1 + "@docusaurus/preset-classic": ^3.1.1 + "@docusaurus/tsconfig": ^3.1.1 + "@docusaurus/types": ^3.1.1 "@mdx-js/react": ^3.0.0 - "@spotify/prettier-config": ^15.0.0 "@swc/core": ^1.3.46 "@types/luxon": ^3.0.0 "@types/webpack-env": ^1.18.0 @@ -4273,17 +4152,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.23.0, browserslist@npm:^4.23.3, browserslist@npm:^4.24.0, browserslist@npm:^4.24.2": - version: 4.24.2 - resolution: "browserslist@npm:4.24.2" +"browserslist@npm:^4.0.0, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1, browserslist@npm:^4.23.3": + version: 4.24.0 + resolution: "browserslist@npm:4.24.0" dependencies: - caniuse-lite: ^1.0.30001669 - electron-to-chromium: ^1.5.41 + caniuse-lite: ^1.0.30001663 + electron-to-chromium: ^1.5.28 node-releases: ^2.0.18 - update-browserslist-db: ^1.1.1 + update-browserslist-db: ^1.1.0 bin: browserslist: cli.js - checksum: cf64085f12132d38638f38937a255edb82c7551b164a98577b055dd79719187a816112f7b97b9739e400c4954cd66479c0d7a843cb816e346f4795dc24fd5d97 + checksum: de200d3eb8d6ed819dad99719099a28fb6ebeb88016a5ac42fbdc11607e910c236a84ca1b0bbf232477d4b88ab64e8ab6aa67557cdd40a73ca9c2834f92ccce0 languageName: node linkType: hard @@ -4412,10 +4291,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001616, caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001669": - version: 1.0.30001677 - resolution: "caniuse-lite@npm:1.0.30001677" - checksum: 34099726620baf4f14fbbe88fec38517208cbe9a47009350b59c7cbbbbd45fcf355afe25d5fa277179660eb0f35f103e68806a07bb33d38bbddb7fde0a4302e4 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001646, caniuse-lite@npm:^1.0.30001663": + version: 1.0.30001668 + resolution: "caniuse-lite@npm:1.0.30001668" + checksum: ce6996901b5883454a8ddb3040f82342277b6a6275876dfefcdecb11f7e472e29877f34cae47c2b674f08f2e71971dd4a2acb9bc01adfe8421b7148a7e9e8297 languageName: node linkType: hard @@ -4426,6 +4305,17 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^2.4.2": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" + dependencies: + ansi-styles: ^3.2.1 + escape-string-regexp: ^1.0.5 + supports-color: ^5.3.0 + checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 + languageName: node + linkType: hard + "chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -4617,6 +4507,15 @@ __metadata: languageName: node linkType: hard +"color-convert@npm:^1.9.0": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: 1.1.3 + checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 + languageName: node + linkType: hard + "color-convert@npm:^2.0.1": version: 2.0.1 resolution: "color-convert@npm:2.0.1" @@ -4626,6 +4525,13 @@ __metadata: languageName: node linkType: hard +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d + languageName: node + linkType: hard + "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" @@ -4773,10 +4679,10 @@ __metadata: languageName: node linkType: hard -"consola@npm:^3.2.3": - version: 3.2.3 - resolution: "consola@npm:3.2.3" - checksum: 32ec70e177dd2385c42e38078958cc7397be91db21af90c6f9faa0b16168b49b1c61d689338604bbb2d64370b9347a35f42a9197663a913d3a405bb0ce728499 +"consola@npm:^2.15.3": + version: 2.15.3 + resolution: "consola@npm:2.15.3" + checksum: 8ef7a09b703ec67ac5c389a372a33b6dc97eda6c9876443a60d76a3076eea0259e7f67a4e54fd5a52f97df73690822d090cf8b7e102b5761348afef7c6d03e28 languageName: node linkType: hard @@ -4854,12 +4760,12 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.38.0, core-js-compat@npm:^3.38.1": - version: 3.39.0 - resolution: "core-js-compat@npm:3.39.0" +"core-js-compat@npm:^3.32.2, core-js-compat@npm:^3.37.1, core-js-compat@npm:^3.38.0": + version: 3.38.1 + resolution: "core-js-compat@npm:3.38.1" dependencies: - browserslist: ^4.24.2 - checksum: 2d7d087c3271d711d03a55203d4756f6288317a1ce35cdc8bafaf1833ef21fd67a92a50cff8dcf7df1325ac63720906ab3cf514c85b238c95f65fca1040f6ad6 + browserslist: ^4.23.3 + checksum: a0a5673bcd59f588f0cd0b59cdacd4712b82909738a87406d334dd412eb3d273ae72b275bdd8e8fef63fca9ef12b42ed651be139c7c44c8a1acb423c8906992e languageName: node linkType: hard @@ -4915,13 +4821,13 @@ __metadata: linkType: hard "cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" dependencies: path-key: ^3.1.0 shebang-command: ^2.0.0 which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + checksum: 8d306efacaf6f3f60e0224c287664093fa9185680b2d195852ba9a863f85d02dcc737094c6e512175f8ee0161f9b87c73c6826034c2422e39de7d6569cf4503b languageName: node linkType: hard @@ -5146,13 +5052,6 @@ __metadata: languageName: node linkType: hard -"debounce@npm:^1.2.1": - version: 1.2.1 - resolution: "debounce@npm:1.2.1" - checksum: 682a89506d9e54fb109526f4da255c5546102fbb8e3ae75eef3b04effaf5d4853756aee97475cd4650641869794e44f410eeb20ace2b18ea592287ab2038519e - languageName: node - linkType: hard - "debug@npm:2.6.9, debug@npm:^2.6.0": version: 2.6.9 resolution: "debug@npm:2.6.9" @@ -5516,10 +5415,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.41": - version: 1.5.50 - resolution: "electron-to-chromium@npm:1.5.50" - checksum: 971f49d0c3f8484225a2ee86f86074c2ef1a3c46c2bad9b2151202c03f5de2f6f0fc41029d0bc634e6d01d067673cbf4916a7f9753f5ec1d5b177cbaca9b2e5a +"electron-to-chromium@npm:^1.5.28": + version: 1.5.36 + resolution: "electron-to-chromium@npm:1.5.36" + checksum: 1f83daebdf88dd4817565660fa68a827bdca2866032d4902bfd79c6f16d97acbd731b63c09029dd5aa1af4aadbe567834cf3c89b52a37602d375352185d68cf4 languageName: node linkType: hard @@ -5651,10 +5550,10 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1, escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 47b029c83de01b0d17ad99ed766347b974b0d628e848de404018f3abee728e987da0d2d370ad4574aa3d5b5bfc368754fd085d69a30f8e75903486ec4b5b709e +"escalade@npm:^3.1.1, escalade@npm:^3.1.2": + version: 3.1.2 + resolution: "escalade@npm:3.1.2" + checksum: 1ec0977aa2772075493002bdbd549d595ff6e9393b1cb0d7d6fcaf78c750da0c158f180938365486f75cb69fba20294351caddfce1b46552a7b6c3cde52eaa02 languageName: node linkType: hard @@ -5955,6 +5854,15 @@ __metadata: languageName: node linkType: hard +"fast-url-parser@npm:1.1.3": + version: 1.1.3 + resolution: "fast-url-parser@npm:1.1.3" + dependencies: + punycode: ^1.3.2 + checksum: 5043d0c4a8d775ff58504d56c096563c11b113e4cb8a2668c6f824a1cd4fb3812e2fdf76537eb24a7ce4ae7def6bd9747da630c617cf2a4b6ce0c42514e4f21c + languageName: node + linkType: hard + "fastq@npm:^1.6.0": version: 1.14.0 resolution: "fastq@npm:1.14.0" @@ -5991,15 +5899,6 @@ __metadata: languageName: node linkType: hard -"figures@npm:^3.2.0": - version: 3.2.0 - resolution: "figures@npm:3.2.0" - dependencies: - escape-string-regexp: ^1.0.5 - checksum: 85a6ad29e9aca80b49b817e7c89ecc4716ff14e3779d9835af554db91bac41c0f289c418923519392a1e582b4d10482ad282021330cd045bb7b80c84152f2a2b - languageName: node - linkType: hard - "file-loader@npm:^6.2.0": version: 6.2.0 resolution: "file-loader@npm:6.2.0" @@ -6082,15 +5981,6 @@ __metadata: languageName: node linkType: hard -"flat@npm:^5.0.2": - version: 5.0.2 - resolution: "flat@npm:5.0.2" - bin: - flat: cli.js - checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d - languageName: node - linkType: hard - "follow-redirects@npm:^1.0.0": version: 1.15.6 resolution: "follow-redirects@npm:1.15.6" @@ -6481,6 +6371,13 @@ __metadata: languageName: node linkType: hard +"has-flag@npm:^3.0.0": + version: 3.0.0 + resolution: "has-flag@npm:3.0.0" + checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b + languageName: node + linkType: hard + "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" @@ -6724,13 +6621,6 @@ __metadata: languageName: node linkType: hard -"html-escaper@npm:^2.0.2": - version: 2.0.2 - resolution: "html-escaper@npm:2.0.2" - checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 - languageName: node - linkType: hard - "html-minifier-terser@npm:^6.0.2": version: 6.1.0 resolution: "html-minifier-terser@npm:6.1.0" @@ -6779,9 +6669,9 @@ __metadata: languageName: node linkType: hard -"html-webpack-plugin@npm:^5.6.0": - version: 5.6.3 - resolution: "html-webpack-plugin@npm:5.6.3" +"html-webpack-plugin@npm:^5.5.3": + version: 5.5.3 + resolution: "html-webpack-plugin@npm:5.5.3" dependencies: "@types/html-minifier-terser": ^6.0.0 html-minifier-terser: ^6.0.2 @@ -6789,14 +6679,8 @@ __metadata: pretty-error: ^4.0.0 tapable: ^2.0.0 peerDependencies: - "@rspack/core": 0.x || 1.x webpack: ^5.20.0 - peerDependenciesMeta: - "@rspack/core": - optional: true - webpack: - optional: true - checksum: 59e7d971b0cfd9ba34c7acaa3c161e43c62596474dd8cd35d7b690498ff5891f21296de0aa1d2e7810348caa657e938461267155dda47913b5eeca7124406270 + checksum: ccf685195739c372ad641bbd0c9100a847904f34eedc7aff3ece7856cd6c78fd3746d2d615af1bb71e5727993fe711b89e9b744f033ed3fde646540bf5d5e954 languageName: node linkType: hard @@ -7043,10 +6927,10 @@ __metadata: languageName: node linkType: hard -"infima@npm:0.2.0-alpha.45": - version: 0.2.0-alpha.45 - resolution: "infima@npm:0.2.0-alpha.45" - checksum: 23e5a33b147cb3940194c23e249001e7988327bb27896b121883442bce42a532248387649eec74d008dadadcddc790fb6842f043f33c78fda35e29f0b720cf8c +"infima@npm:0.2.0-alpha.44": + version: 0.2.0-alpha.44 + resolution: "infima@npm:0.2.0-alpha.44" + checksum: e9871f4056c0c8b311fcd32e2864d23a8f6807af5ff32d3c4d8271ad9971b5a7ea5016787a6b215893bb3e9f5f14326816bc05151d576dd375b0d79279cdfa8b languageName: node linkType: hard @@ -7327,6 +7211,13 @@ __metadata: languageName: node linkType: hard +"is-plain-object@npm:^5.0.0": + version: 5.0.0 + resolution: "is-plain-object@npm:5.0.0" + checksum: e32d27061eef62c0847d303125440a38660517e586f2f3db7c9d179ae5b6674ab0f469d519b2e25c147a1a3bc87156d0d5f4d8821e0ce4a9ee7fe1fcf11ce45c + languageName: node + linkType: hard + "is-reference@npm:^3.0.0": version: 3.0.1 resolution: "is-reference@npm:3.0.1" @@ -7504,12 +7395,21 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^3.0.2, jsesc@npm:~3.0.2": - version: 3.0.2 - resolution: "jsesc@npm:3.0.2" +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" bin: jsesc: bin/jsesc - checksum: a36d3ca40574a974d9c2063bf68c2b6141c20da8f2a36bd3279fc802563f35f0527a6c828801295bdfb2803952cf2cf387786c2c90ed564f88d5782475abfe3c + checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + languageName: node + linkType: hard + +"jsesc@npm:~0.5.0": + version: 0.5.0 + resolution: "jsesc@npm:0.5.0" + bin: + jsesc: bin/jsesc + checksum: b8b44cbfc92f198ad972fba706ee6a1dfa7485321ee8c0b25f5cedd538dcb20cde3197de16a7265430fce8277a12db066219369e3d51055038946039f6e20e17 languageName: node linkType: hard @@ -7619,116 +7519,6 @@ __metadata: languageName: node linkType: hard -"lightningcss-darwin-arm64@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-darwin-arm64@npm:1.28.1" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"lightningcss-darwin-x64@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-darwin-x64@npm:1.28.1" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"lightningcss-freebsd-x64@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-freebsd-x64@npm:1.28.1" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"lightningcss-linux-arm-gnueabihf@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-linux-arm-gnueabihf@npm:1.28.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"lightningcss-linux-arm64-gnu@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-linux-arm64-gnu@npm:1.28.1" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"lightningcss-linux-arm64-musl@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-linux-arm64-musl@npm:1.28.1" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"lightningcss-linux-x64-gnu@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-linux-x64-gnu@npm:1.28.1" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"lightningcss-linux-x64-musl@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-linux-x64-musl@npm:1.28.1" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"lightningcss-win32-arm64-msvc@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-win32-arm64-msvc@npm:1.28.1" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"lightningcss-win32-x64-msvc@npm:1.28.1": - version: 1.28.1 - resolution: "lightningcss-win32-x64-msvc@npm:1.28.1" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"lightningcss@npm:^1.27.0": - version: 1.28.1 - resolution: "lightningcss@npm:1.28.1" - dependencies: - detect-libc: ^1.0.3 - lightningcss-darwin-arm64: 1.28.1 - lightningcss-darwin-x64: 1.28.1 - lightningcss-freebsd-x64: 1.28.1 - lightningcss-linux-arm-gnueabihf: 1.28.1 - lightningcss-linux-arm64-gnu: 1.28.1 - lightningcss-linux-arm64-musl: 1.28.1 - lightningcss-linux-x64-gnu: 1.28.1 - lightningcss-linux-x64-musl: 1.28.1 - lightningcss-win32-arm64-msvc: 1.28.1 - lightningcss-win32-x64-msvc: 1.28.1 - dependenciesMeta: - lightningcss-darwin-arm64: - optional: true - lightningcss-darwin-x64: - optional: true - lightningcss-freebsd-x64: - optional: true - lightningcss-linux-arm-gnueabihf: - optional: true - lightningcss-linux-arm64-gnu: - optional: true - lightningcss-linux-arm64-musl: - optional: true - lightningcss-linux-x64-gnu: - optional: true - lightningcss-linux-x64-musl: - optional: true - lightningcss-win32-arm64-msvc: - optional: true - lightningcss-win32-x64-msvc: - optional: true - checksum: 6ac8302021b2a917c16991310ff8c588c9163cad1c0abe271a44c2b58c05de03fcbde64d49f53dbe449402def02e4a4e11754da23bcb2a99d86bfbc93424333c - languageName: node - linkType: hard - "lilconfig@npm:^3.1.1": version: 3.1.2 resolution: "lilconfig@npm:3.1.2" @@ -7803,6 +7593,27 @@ __metadata: languageName: node linkType: hard +"lodash.escape@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.escape@npm:4.0.1" + checksum: fcb54f457497256964d619d5cccbd80a961916fca60df3fe0fa3e7f052715c2944c0ed5aefb4f9e047d127d44aa2d55555f3350cb42c6549e9e293fb30b41e7f + languageName: node + linkType: hard + +"lodash.flatten@npm:^4.4.0": + version: 4.4.0 + resolution: "lodash.flatten@npm:4.4.0" + checksum: 0ac34a393d4b795d4b7421153d27c13ae67e08786c9cbb60ff5b732210d46f833598eee3fb3844bb10070e8488efe390ea53bb567377e0cb47e9e630bf0811cb + languageName: node + linkType: hard + +"lodash.invokemap@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.invokemap@npm:4.6.0" + checksum: 646ceebbefbcb6da301f8c2868254680fd0bcdc6ada470495d9ae49c9c32938829c1b38a38c95d0258409a9655f85db404b16e648381c7450b7ed3d9c52d8808 + languageName: node + linkType: hard + "lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" @@ -7810,6 +7621,13 @@ __metadata: languageName: node linkType: hard +"lodash.pullall@npm:^4.2.0": + version: 4.2.0 + resolution: "lodash.pullall@npm:4.2.0" + checksum: 7a5fbaedf186ec197ce1e0b9ba1d88a89773ebaf6a8291c7d273838cac59cb3b339cf36ef00e94172862ee84d2304c38face161846f08f5581d0553dcbdcd090 + languageName: node + linkType: hard + "lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" @@ -7817,6 +7635,13 @@ __metadata: languageName: node linkType: hard +"lodash.uniqby@npm:^4.7.0": + version: 4.7.0 + resolution: "lodash.uniqby@npm:4.7.0" + checksum: 659264545a95726d1493123345aad8cbf56e17810fa9a0b029852c6d42bc80517696af09d99b23bef1845d10d95e01b8b4a1da578f22aeba7a30d3e0022a4938 + languageName: node + linkType: hard + "lodash@npm:^4.17.20, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -7921,15 +7746,6 @@ __metadata: languageName: node linkType: hard -"markdown-table@npm:^2.0.0": - version: 2.0.0 - resolution: "markdown-table@npm:2.0.0" - dependencies: - repeat-string: ^1.0.0 - checksum: 9bb634a9300016cbb41216c1eab44c74b6b7083ac07872e296f900a29449cf0e260ece03fa10c3e9784ab94c61664d1d147da0315f95e1336e2bdcc025615c90 - languageName: node - linkType: hard - "markdown-table@npm:^3.0.0": version: 3.0.3 resolution: "markdown-table@npm:3.0.3" @@ -8818,15 +8634,14 @@ __metadata: languageName: node linkType: hard -"mini-css-extract-plugin@npm:^2.9.1": - version: 2.9.2 - resolution: "mini-css-extract-plugin@npm:2.9.2" +"mini-css-extract-plugin@npm:^2.7.6": + version: 2.7.6 + resolution: "mini-css-extract-plugin@npm:2.7.6" dependencies: schema-utils: ^4.0.0 - tapable: ^2.2.1 peerDependencies: webpack: ^5.0.0 - checksum: 67a1f75359371a7776108999d472ae0942ccd904401e364e3a2c710d4b6fec61c4f53288594fcac35891f009e6df8825a00dfd3bfe4bcec0f862081d1f7cad50 + checksum: be6f7cefc6275168eb0a6b8fe977083a18c743c9612c9f00e6c1a62c3393ca7960e93fba1a7ebb09b75f36a0204ad087d772c1ef574bc29c90c0e8175a3c0b83 languageName: node linkType: hard @@ -9145,18 +8960,6 @@ __metadata: languageName: node linkType: hard -"null-loader@npm:^4.0.1": - version: 4.0.1 - resolution: "null-loader@npm:4.0.1" - dependencies: - loader-utils: ^2.0.0 - schema-utils: ^3.0.0 - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: eeb4c4dd2f8f41e46f5665e4500359109e95ec1028a178a60e0161984906572da7dd87644bcc3cb29f0125d77e2b2508fb4f3813cfb1c6604a15865beb4b987b - languageName: node - linkType: hard - "object-assign@npm:^4.1.1": version: 4.1.1 resolution: "object-assign@npm:4.1.1" @@ -9496,10 +9299,10 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:3.3.0": - version: 3.3.0 - resolution: "path-to-regexp@npm:3.3.0" - checksum: bb249d08804f7961dd44fb175466c900b893c56e909db8e2a66ec12b9d9a964af269eb7a50892c933f52b47315953dfdb4279639fbce20977c3625a9ef3055fe +"path-to-regexp@npm:2.2.1": + version: 2.2.1 + resolution: "path-to-regexp@npm:2.2.1" + checksum: b921a74e7576e25b06ad1635abf7e8125a29220d2efc2b71d74b9591f24a27e6f09078fa9a1b27516a097ea0637b7cab79d19b83d7f36a8ef3ef5422770e89d9 languageName: node linkType: hard @@ -9530,10 +9333,10 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.0": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 +"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: fa68166d1f56009fc02a34cdfd112b0dd3cf1ef57667ac57281f714065558c01828cdf4f18600ad6851cbe0093952ed0660b1e0156bddf2184b6aaf5817553a5 languageName: node linkType: hard @@ -10120,6 +9923,13 @@ __metadata: languageName: node linkType: hard +"punycode@npm:^1.3.2": + version: 1.4.1 + resolution: "punycode@npm:1.4.1" + checksum: fa6e698cb53db45e4628559e557ddaf554103d2a96a1d62892c8f4032cd3bc8871796cae9eabc1bc700e2b6677611521ce5bb1d9a27700086039965d0cf34518 + languageName: node + linkType: hard + "punycode@npm:^2.1.0": version: 2.1.1 resolution: "punycode@npm:2.1.1" @@ -10454,12 +10264,12 @@ __metadata: languageName: node linkType: hard -"regenerate-unicode-properties@npm:^10.2.0": - version: 10.2.0 - resolution: "regenerate-unicode-properties@npm:10.2.0" +"regenerate-unicode-properties@npm:^10.1.0": + version: 10.1.0 + resolution: "regenerate-unicode-properties@npm:10.1.0" dependencies: regenerate: ^1.4.2 - checksum: d5c5fc13f8b8d7e16e791637a4bfef741f8d70e267d51845ee7d5404a32fa14c75b181c4efba33e4bff8b0000a2f13e9773593713dfe5b66597df4259275ce63 + checksum: b1a8929588433ab8b9dc1a34cf3665b3b472f79f2af6ceae00d905fc496b332b9af09c6718fb28c730918f19a00dc1d7310adbaa9b72a2ec7ad2f435da8ace17 languageName: node linkType: hard @@ -10486,17 +10296,17 @@ __metadata: languageName: node linkType: hard -"regexpu-core@npm:^6.1.1": - version: 6.1.1 - resolution: "regexpu-core@npm:6.1.1" +"regexpu-core@npm:^5.3.1": + version: 5.3.2 + resolution: "regexpu-core@npm:5.3.2" dependencies: + "@babel/regjsgen": ^0.8.0 regenerate: ^1.4.2 - regenerate-unicode-properties: ^10.2.0 - regjsgen: ^0.8.0 - regjsparser: ^0.11.0 + regenerate-unicode-properties: ^10.1.0 + regjsparser: ^0.9.1 unicode-match-property-ecmascript: ^2.0.0 unicode-match-property-value-ecmascript: ^2.1.0 - checksum: ed8e3784e81b816b237313688f28b4695d30d4e0f823dfdf130fd4313c629ac6ec67650563867a6ca9a2435f33e79f3a5001c651aee52791e346213a948de0ff + checksum: 95bb97088419f5396e07769b7de96f995f58137ad75fac5811fb5fe53737766dfff35d66a0ee66babb1eb55386ef981feaef392f9df6d671f3c124812ba24da2 languageName: node linkType: hard @@ -10518,21 +10328,14 @@ __metadata: languageName: node linkType: hard -"regjsgen@npm:^0.8.0": - version: 0.8.0 - resolution: "regjsgen@npm:0.8.0" - checksum: a1d925ff14a4b2be774e45775ee6b33b256f89c42d480e6d85152d2133f18bd3d6af662161b226fa57466f7efec367eaf7ccd2a58c0ec2a1306667ba2ad07b0d - languageName: node - linkType: hard - -"regjsparser@npm:^0.11.0": - version: 0.11.2 - resolution: "regjsparser@npm:0.11.2" +"regjsparser@npm:^0.9.1": + version: 0.9.1 + resolution: "regjsparser@npm:0.9.1" dependencies: - jsesc: ~3.0.2 + jsesc: ~0.5.0 bin: regjsparser: bin/parser - checksum: 500ab99d6174aef18b43518f4b1f217192459621b0505ad6e8cbbec8135a83e64491077843b4ad06249a207ffecd6566f3db1895a7c5df98f786b4b0edcc9820 + checksum: 5e1b76afe8f1d03c3beaf9e0d935dd467589c3625f6d65fb8ffa14f224d783a0fed4bf49c2c1b8211043ef92b6117313419edf055a098ed8342e340586741afc languageName: node linkType: hard @@ -10664,13 +10467,6 @@ __metadata: languageName: node linkType: hard -"repeat-string@npm:^1.0.0": - version: 1.6.1 - resolution: "repeat-string@npm:1.6.1" - checksum: 1b809fc6db97decdc68f5b12c4d1a671c8e3f65ec4a40c238bc5200e44e85bcc52a54f78268ab9c29fcf5fe4f1343e805420056d1f30fa9a9ee4c2d93e3cc6c0 - languageName: node - linkType: hard - "require-from-string@npm:^2.0.2": version: 2.0.2 resolution: "require-from-string@npm:2.0.2" @@ -11008,18 +10804,19 @@ __metadata: languageName: node linkType: hard -"serve-handler@npm:^6.1.6": - version: 6.1.6 - resolution: "serve-handler@npm:6.1.6" +"serve-handler@npm:^6.1.5": + version: 6.1.5 + resolution: "serve-handler@npm:6.1.5" dependencies: bytes: 3.0.0 content-disposition: 0.5.2 + fast-url-parser: 1.1.3 mime-types: 2.1.18 minimatch: 3.1.2 path-is-inside: 1.0.2 - path-to-regexp: 3.3.0 + path-to-regexp: 2.2.1 range-parser: 1.2.0 - checksum: eb26201e699ac4694fb16f9aaf932330f6b1159e9d9496261baa23caf1e81322afcfd2b5f5f2b306b133298c03a8395a3c13b56fde5d70b331014b3a5ab7217f + checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc languageName: node linkType: hard @@ -11369,10 +11166,10 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.7.0": - version: 3.7.0 - resolution: "std-env@npm:3.7.0" - checksum: 4f489d13ff2ab838c9acd4ed6b786b51aa52ecacdfeaefe9275fcb220ff2ac80c6e95674723508fd29850a694569563a8caaaea738eb82ca16429b3a0b50e510 +"std-env@npm:^3.0.1": + version: 3.3.1 + resolution: "std-env@npm:3.3.1" + checksum: c4f59ecd2cb52041ce1785776d28a1aa56d346b6c4efcb8473e7e801eed1ac7612332dcee242d0b35948f35f745cceb6e226b5e825b59e588b262dca6be2b8aa languageName: node linkType: hard @@ -11437,7 +11234,7 @@ __metadata: languageName: node linkType: hard -"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: @@ -11513,6 +11310,15 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^5.3.0": + version: 5.5.0 + resolution: "supports-color@npm:5.5.0" + dependencies: + has-flag: ^3.0.0 + checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac + languageName: node + linkType: hard + "supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" @@ -11562,7 +11368,7 @@ __metadata: languageName: node linkType: hard -"swc-loader@npm:^0.2.3, swc-loader@npm:^0.2.6": +"swc-loader@npm:^0.2.3": version: 0.2.6 resolution: "swc-loader@npm:0.2.6" dependencies: @@ -11581,7 +11387,7 @@ __metadata: languageName: node linkType: hard -"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0, tapable@npm:^2.2.1": +"tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0": version: 2.2.1 resolution: "tapable@npm:2.2.1" checksum: 3b7a1b4d86fa940aad46d9e73d1e8739335efd4c48322cb37d073eb6f80f5281889bf0320c6d8ffcfa1a0dd5bfdbd0f9d037e252ef972aca595330538aac4d51 @@ -11666,6 +11472,13 @@ __metadata: languageName: node linkType: hard +"to-fast-properties@npm:^2.0.0": + version: 2.0.0 + resolution: "to-fast-properties@npm:2.0.0" + checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -11710,13 +11523,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.21.3": - version: 0.21.3 - resolution: "type-fest@npm:0.21.3" - checksum: e6b32a3b3877f04339bae01c193b273c62ba7bfc9e325b8703c4ee1b32dc8fe4ef5dfa54bf78265e069f7667d058e360ae0f37be5af9f153b22382cd55a9afe0 - languageName: node - linkType: hard - "type-fest@npm:^1.0.1": version: 1.4.0 resolution: "type-fest@npm:1.4.0" @@ -11931,17 +11737,17 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.1": - version: 1.1.1 - resolution: "update-browserslist-db@npm:1.1.1" +"update-browserslist-db@npm:^1.1.0": + version: 1.1.0 + resolution: "update-browserslist-db@npm:1.1.0" dependencies: - escalade: ^3.2.0 - picocolors: ^1.1.0 + escalade: ^3.1.2 + picocolors: ^1.0.1 peerDependencies: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: 2ea11bd2562122162c3e438d83a1f9125238c0844b6d16d366e3276d0c0acac6036822dc7df65fc5a89c699cdf9f174acf439c39bedf3f9a2f3983976e4b4c3e + checksum: 7b74694d96f0c360f01b702e72353dc5a49df4fe6663d3ee4e5c628f061576cddf56af35a3a886238c01dd3d8f231b7a86a8ceaa31e7a9220ae31c1c1238e562 languageName: node linkType: hard @@ -12101,29 +11907,34 @@ __metadata: languageName: node linkType: hard -"webpack-bundle-analyzer@npm:^4.10.2": - version: 4.10.2 - resolution: "webpack-bundle-analyzer@npm:4.10.2" +"webpack-bundle-analyzer@npm:^4.9.0": + version: 4.9.1 + resolution: "webpack-bundle-analyzer@npm:4.9.1" dependencies: "@discoveryjs/json-ext": 0.5.7 acorn: ^8.0.4 acorn-walk: ^8.0.0 commander: ^7.2.0 - debounce: ^1.2.1 escape-string-regexp: ^4.0.0 gzip-size: ^6.0.0 - html-escaper: ^2.0.2 + is-plain-object: ^5.0.0 + lodash.debounce: ^4.0.8 + lodash.escape: ^4.0.1 + lodash.flatten: ^4.4.0 + lodash.invokemap: ^4.6.0 + lodash.pullall: ^4.2.0 + lodash.uniqby: ^4.7.0 opener: ^1.5.2 picocolors: ^1.0.0 sirv: ^2.0.3 ws: ^7.3.1 bin: webpack-bundle-analyzer: lib/bin/analyzer.js - checksum: 4f0275e7d87bb6203a618ca5d2d4953943979d986fa2b91be1bf1ad0bcd22bec13398803273d11699f9fbcf106896311208a72d63fe5f8a47b687a226e598dc1 + checksum: 7e891c28d5a903242893e55ecc714fa01d7ad6bedade143235c07091b235915349812fa048968462781d59187507962f38b6c61ed7d25fb836ba0ac0ee919a39 languageName: node linkType: hard -"webpack-dev-middleware@npm:^5.3.4": +"webpack-dev-middleware@npm:^5.3.1": version: 5.3.4 resolution: "webpack-dev-middleware@npm:5.3.4" dependencies: @@ -12138,9 +11949,9 @@ __metadata: languageName: node linkType: hard -"webpack-dev-server@npm:^4.15.2": - version: 4.15.2 - resolution: "webpack-dev-server@npm:4.15.2" +"webpack-dev-server@npm:^4.15.1": + version: 4.15.1 + resolution: "webpack-dev-server@npm:4.15.1" dependencies: "@types/bonjour": ^3.5.9 "@types/connect-history-api-fallback": ^1.3.5 @@ -12170,7 +11981,7 @@ __metadata: serve-index: ^1.9.1 sockjs: ^0.3.24 spdy: ^4.0.2 - webpack-dev-middleware: ^5.3.4 + webpack-dev-middleware: ^5.3.1 ws: ^8.13.0 peerDependencies: webpack: ^4.37.0 || ^5.0.0 @@ -12181,7 +11992,7 @@ __metadata: optional: true bin: webpack-dev-server: bin/webpack-dev-server.js - checksum: 123507129cb4d55fdc5fabdd177574f31133605748372bb11353307b7a583ef25c6fd27b6addf56bf070ba44c88d5da861771c2ec55f52405082ec9efd01f039 + checksum: cd0063b068d2b938fd76c412d555374186ac2fa84bbae098265212ed50a5c15d6f03aa12a5a310c544a242943eb58c0bfde4c296d5c36765c182f53799e1bc71 languageName: node linkType: hard @@ -12195,17 +12006,6 @@ __metadata: languageName: node linkType: hard -"webpack-merge@npm:^6.0.1": - version: 6.0.1 - resolution: "webpack-merge@npm:6.0.1" - dependencies: - clone-deep: ^4.0.1 - flat: ^5.0.2 - wildcard: ^2.0.1 - checksum: e8a604c686b944605a1c57cc7b75e886ab902dc5ffdd15259a092c5c2dd5f58868fe39f995ea4bad4f189e38843b061c4ae1eb22822d7169813f4adab571dc3d - languageName: node - linkType: hard - "webpack-sources@npm:^3.2.3": version: 3.2.3 resolution: "webpack-sources@npm:3.2.3" @@ -12213,17 +12013,17 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5.88.1, webpack@npm:^5.95.0": - version: 5.96.1 - resolution: "webpack@npm:5.96.1" +"webpack@npm:^5.88.1": + version: 5.95.0 + resolution: "webpack@npm:5.95.0" dependencies: - "@types/eslint-scope": ^3.7.7 - "@types/estree": ^1.0.6 + "@types/estree": ^1.0.5 "@webassemblyjs/ast": ^1.12.1 "@webassemblyjs/wasm-edit": ^1.12.1 "@webassemblyjs/wasm-parser": ^1.12.1 - acorn: ^8.14.0 - browserslist: ^4.24.0 + acorn: ^8.7.1 + acorn-import-attributes: ^1.9.5 + browserslist: ^4.21.10 chrome-trace-event: ^1.0.2 enhanced-resolve: ^5.17.1 es-module-lexer: ^1.2.1 @@ -12245,25 +12045,21 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: ec3662f64895fae408440a997f87299e374c9d9f911f77b880bab46402f52221c7836bdf101fc2556338d07fc7cb86da50661f944eb1d1041a8361a5b9247876 + checksum: 0c3dfe288de4d62f8f3dc25478a618894883cab739121330763b7847e43304630ea2815ae2351a5f8ff6ab7c9642caf530d503d89bda261fe2cd220e524dd5d1 languageName: node linkType: hard -"webpackbar@npm:^6.0.1": - version: 6.0.1 - resolution: "webpackbar@npm:6.0.1" +"webpackbar@npm:^5.0.2": + version: 5.0.2 + resolution: "webpackbar@npm:5.0.2" dependencies: - ansi-escapes: ^4.3.2 - chalk: ^4.1.2 - consola: ^3.2.3 - figures: ^3.2.0 - markdown-table: ^2.0.0 + chalk: ^4.1.0 + consola: ^2.15.3 pretty-time: ^1.1.0 - std-env: ^3.7.0 - wrap-ansi: ^7.0.0 + std-env: ^3.0.1 peerDependencies: webpack: 3 || 4 || 5 - checksum: e9ba314452486230668ab34aea7c3494866dbe29e327e9201551a839000ee7e878d8a47b8977acb76ec9443b4257dfcdb05bae9bbc27ffb21793d2bed7907687 + checksum: 214a734b1d4d391eb8271ed1b11085f0efe6831e93f641229b292abfd6fea871422dce121612511c17ae8047522be6d65c1a2666cabb396c79549816a3612338 languageName: node linkType: hard @@ -12325,21 +12121,10 @@ __metadata: languageName: node linkType: hard -"wildcard@npm:^2.0.0, wildcard@npm:^2.0.1": - version: 2.0.1 - resolution: "wildcard@npm:2.0.1" - checksum: e0c60a12a219e4b12065d1199802d81c27b841ed6ad6d9d28240980c73ceec6f856771d575af367cbec2982d9ae7838759168b551776577f155044f5a5ba843c - languageName: node - linkType: hard - -"wrap-ansi@npm:^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b +"wildcard@npm:^2.0.0": + version: 2.0.0 + resolution: "wildcard@npm:2.0.0" + checksum: 1f4fe4c03dfc492777c60f795bbba597ac78794f1b650d68f398fbee9adb765367c516ebd4220889b6a81e9626e7228bbe0d66237abb311573c2ee1f4902a5ad languageName: node linkType: hard diff --git a/mkdocs.yml b/mkdocs.yml index 76467e9476..748cdd8232 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -30,12 +30,16 @@ nav: - Configuring App with plugins: 'getting-started/configure-app-with-plugins.md' - Customize the look-and-feel of your App: 'getting-started/app-custom-theme.md' - Customizing your Homepage: 'getting-started/homepage.md' + - Deployment: + - Deploying Backstage: 'deployment/index.md' + - Scaling: 'deployment/scaling.md' + - Docker: 'deployment/docker.md' + - Kubernetes: 'deployment/k8s.md' - Using Backstage: - Logging in: 'getting-started/logging-in.md' - Register a component: 'getting-started/register-a-component.md' - Create a component: 'getting-started/create-a-component.md' - Keeping Backstage Updated: 'getting-started/keeping-backstage-updated.md' - - Key Concepts: 'getting-started/concepts.md' - Core Features: - Software Catalog: - Overview: 'features/software-catalog/index.md' @@ -189,13 +193,6 @@ nav: - Debugging Backstage: 'tooling/local-dev/debugging.md' - Profiling Backstage: 'tooling/local-dev/profiling.md' - Package Metadata: 'tooling/package-metadata.md' - - Deployment: - - Deploying Backstage: 'deployment/index.md' - - Scaling: 'deployment/scaling.md' - - Docker: 'deployment/docker.md' - - Kubernetes: 'deployment/k8s.md' - - Heroku: 'deployment/heroku.md' - - Koyeb: 'deployment/koyeb.md' - Designing for Backstage: - Design: 'dls/design.md' - Component Design Guidelines: 'dls/component-design-guidelines.md' @@ -230,6 +227,7 @@ nav: - ADR011 - Plugin Package Structure: 'architecture-decisions/adr011-plugin-package-structure.md' - ADR012 - Use Luxon Locale: 'architecture-decisions/adr012-use-luxon-locale-and-date-presets.md' - ADR013 - Use node-fetch: 'architecture-decisions/adr013-use-node-fetch.md' + - ADR014 - Use fetch: 'architecture-decisions/adr014-use-fetch.md' - FAQ: - Overview: 'faq/index.md' - Product FAQ: 'faq/product.md' diff --git a/package.json b/package.json index 0e63c3c09f..9c4a772ebc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "root", - "version": "1.33.0-next.3", + "version": "1.34.0-next.2", "private": true, "repository": { "type": "git", @@ -49,9 +49,9 @@ "storybook": "yarn ./storybook run storybook", "techdocs-cli": "node scripts/techdocs-cli.js", "techdocs-cli:dev": "cross-env TECHDOCS_CLI_DEV_MODE=true node scripts/techdocs-cli.js", - "test": "backstage-cli repo test", - "test:all": "backstage-cli repo test --coverage", - "test:e2e": "playwright test", + "test": "NODE_OPTIONS=--no-node-snapshot backstage-cli repo test", + "test:all": "NODE_OPTIONS=--no-node-snapshot backstage-cli repo test --coverage", + "test:e2e": "NODE_OPTIONS=--no-node-snapshot playwright test", "tsc": "tsc", "tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false" }, @@ -83,7 +83,7 @@ "node ./scripts/verify-lockfile-duplicates --fix" ] }, - "prettier": "@spotify/prettier-config", + "prettier": "@backstage/cli/config/prettier", "resolutions": { "@changesets/assemble-release-plan@^6.0.0": "patch:@changesets/assemble-release-plan@npm%3A6.0.0#./.yarn/patches/@changesets-assemble-release-plan-npm-6.0.0-f7b3005037.patch", "@material-ui/pickers@^3.2.10": "patch:@material-ui/pickers@npm%3A3.3.11#./.yarn/patches/@material-ui-pickers-npm-3.3.11-1c8f68ea20.patch", @@ -108,8 +108,9 @@ "@octokit/rest": "^19.0.3", "@playwright/test": "^1.32.3", "@spotify/eslint-plugin": "^15.0.0", - "@spotify/prettier-config": "^15.0.0", "@techdocs/cli": "workspace:*", + "@types/cacheable-request": "^8.3.6", + "@types/memjs": "^1.3.3", "@types/node": "^20.16.0", "@types/webpack": "^5.28.0", "array-to-table": "^1.0.1", diff --git a/packages/app-defaults/CHANGELOG.md b/packages/app-defaults/CHANGELOG.md index 3b95e8aefd..660d8d4ebb 100644 --- a/packages/app-defaults/CHANGELOG.md +++ b/packages/app-defaults/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/app-defaults +## 1.5.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 1.5.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## 1.5.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + +## 1.5.13 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + ## 1.5.13-next.2 ### Patch Changes diff --git a/packages/app-defaults/package.json b/packages/app-defaults/package.json index fbf6eabeae..1a0c1f0d74 100644 --- a/packages/app-defaults/package.json +++ b/packages/app-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/app-defaults", - "version": "1.5.13-next.2", + "version": "1.5.15-next.2", "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 f00bc15813..0ff4bde808 100644 --- a/packages/app-next-example-plugin/CHANGELOG.md +++ b/packages/app-next-example-plugin/CHANGELOG.md @@ -1,5 +1,37 @@ # app-next-example-plugin +## 0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## 0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## 0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-components@0.16.2-next.0 + +## 0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/frontend-plugin-api@0.9.1 + ## 0.0.17-next.2 ### Patch Changes diff --git a/packages/app-next-example-plugin/package.json b/packages/app-next-example-plugin/package.json index 07d3c80ff2..acbe3831c4 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.17-next.2", + "version": "0.0.18-next.2", "description": "Backstage internal example plugin", "backstage": { "role": "frontend-plugin", diff --git a/packages/app-next/CHANGELOG.md b/packages/app-next/CHANGELOG.md index 1a05132568..354ae53a70 100644 --- a/packages/app-next/CHANGELOG.md +++ b/packages/app-next/CHANGELOG.md @@ -1,5 +1,185 @@ # example-app-next +## 0.0.18-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/plugin-notifications@0.5.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/plugin-scaffolder@1.27.2-next.2 + - @backstage/plugin-api-docs@0.12.2-next.2 + - @backstage/plugin-catalog-graph@0.4.14-next.2 + - @backstage/plugin-catalog-import@0.12.8-next.2 + - @backstage/plugin-org@0.6.34-next.2 + - @backstage/plugin-user-settings@0.8.17-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-defaults@0.1.4-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-app@0.1.4-next.2 + - @backstage/plugin-app-visualizer@0.1.14-next.2 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.2 + - @backstage/plugin-home@0.8.3-next.2 + - @backstage/plugin-kubernetes@0.12.2-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.2 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-search@1.4.21-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-signals@0.0.14-next.2 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## 0.0.18-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.8.3-next.1 + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-api-docs@0.12.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-catalog-graph@0.4.14-next.1 + - @backstage/plugin-catalog-import@0.12.8-next.1 + - @backstage/plugin-kubernetes@0.12.2-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.1 + - @backstage/plugin-org@0.6.34-next.1 + - @backstage/plugin-scaffolder@1.27.2-next.1 + - @backstage/plugin-search@1.4.21-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/plugin-user-settings@0.8.17-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-defaults@0.1.4-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-app@0.1.4-next.1 + - @backstage/plugin-app-visualizer@0.1.14-next.1 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.1 + - @backstage/plugin-notifications@0.4.2-next.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-signals@0.0.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## 0.0.18-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-scaffolder@1.27.2-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-search@1.4.21-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/plugin-home@0.8.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-api-docs@0.12.2-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/frontend-defaults@0.1.4-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-app-visualizer@0.1.14-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.14-next.0 + - @backstage/plugin-catalog-import@0.12.8-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.0 + - @backstage/plugin-kubernetes@0.12.2-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.0 + - @backstage/plugin-notifications@0.4.2-next.0 + - @backstage/plugin-org@0.6.34-next.0 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-signals@0.0.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + - @backstage/plugin-user-settings@0.8.17-next.0 + +## 0.0.17 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-api-docs@0.12.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-notifications@0.4.0 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/plugin-search@1.4.19 + - @backstage/plugin-org@0.6.32 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder@1.27.0 + - @backstage/plugin-catalog-import@0.12.6 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes@0.12.0 + - @backstage/plugin-home@0.8.1 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/plugin-app-visualizer@0.1.12 + - @backstage/core-app-api@1.15.2 + - @backstage/frontend-defaults@0.1.2 + - @backstage/plugin-signals@0.0.12 + - @backstage/plugin-kubernetes-cluster@0.0.18 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-app@0.1.2 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.12 + - @backstage/plugin-catalog-unprocessed-entities@0.2.10 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.17 + - @backstage/plugin-user-settings@0.8.15 + ## 0.0.17-next.3 ### Patch Changes diff --git a/packages/app-next/package.json b/packages/app-next/package.json index 75fc296ede..c39fac7e6a 100644 --- a/packages/app-next/package.json +++ b/packages/app-next/package.json @@ -1,6 +1,6 @@ { "name": "example-app-next", - "version": "0.0.17-next.3", + "version": "0.0.18-next.2", "backstage": { "role": "frontend" }, diff --git a/packages/app/CHANGELOG.md b/packages/app/CHANGELOG.md index 0abd04bf1a..fd244dde7e 100644 --- a/packages/app/CHANGELOG.md +++ b/packages/app/CHANGELOG.md @@ -1,5 +1,169 @@ # example-app +## 0.2.104-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/plugin-notifications@0.5.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/plugin-scaffolder@1.27.2-next.2 + - @backstage/plugin-api-docs@0.12.2-next.2 + - @backstage/plugin-catalog-graph@0.4.14-next.2 + - @backstage/plugin-catalog-import@0.12.8-next.2 + - @backstage/plugin-org@0.6.34-next.2 + - @backstage/plugin-user-settings@0.8.17-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.2 + - @backstage/plugin-devtools@0.1.22-next.2 + - @backstage/plugin-home@0.8.3-next.2 + - @backstage/plugin-kubernetes@0.12.2-next.2 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.2 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-search@1.4.21-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-signals@0.0.14-next.2 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## 0.2.104-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-home@0.8.3-next.1 + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-api-docs@0.12.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-catalog-graph@0.4.14-next.1 + - @backstage/plugin-catalog-import@0.12.8-next.1 + - @backstage/plugin-kubernetes@0.12.2-next.1 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.1 + - @backstage/plugin-org@0.6.34-next.1 + - @backstage/plugin-scaffolder@1.27.2-next.1 + - @backstage/plugin-search@1.4.21-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/plugin-user-settings@0.8.17-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.1 + - @backstage/plugin-devtools@0.1.22-next.1 + - @backstage/plugin-notifications@0.4.2-next.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-signals@0.0.14-next.1 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## 0.2.104-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-scaffolder@1.27.2-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-search@1.4.21-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/plugin-home@0.8.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-api-docs@0.12.2-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.14-next.0 + - @backstage/plugin-catalog-import@0.12.8-next.0 + - @backstage/plugin-catalog-unprocessed-entities@0.2.12-next.0 + - @backstage/plugin-devtools@0.1.22-next.0 + - @backstage/plugin-kubernetes@0.12.2-next.0 + - @backstage/plugin-kubernetes-cluster@0.0.20-next.0 + - @backstage/plugin-notifications@0.4.2-next.0 + - @backstage/plugin-org@0.6.34-next.0 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-signals@0.0.14-next.0 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.19-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + - @backstage/plugin-user-settings@0.8.17-next.0 + +## 0.2.103 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-api-docs@0.12.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-notifications@0.4.0 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/plugin-search@1.4.19 + - @backstage/plugin-org@0.6.32 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder@1.27.0 + - @backstage/plugin-catalog-import@0.12.6 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes@0.12.0 + - @backstage/plugin-home@0.8.1 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-app-api@1.15.2 + - @backstage/plugin-signals@0.0.12 + - @backstage/plugin-kubernetes-cluster@0.0.18 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-app-api@0.10.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-graph@0.4.12 + - @backstage/plugin-catalog-unprocessed-entities@0.2.10 + - @backstage/plugin-devtools@0.1.20 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-module-addons-contrib@1.1.17 + - @backstage/plugin-user-settings@0.8.15 + ## 0.2.103-next.3 ### Patch Changes diff --git a/packages/app/package.json b/packages/app/package.json index a0607e9bb8..67228f4b74 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -1,6 +1,6 @@ { "name": "example-app", - "version": "0.2.103-next.3", + "version": "0.2.104-next.2", "backstage": { "role": "frontend" }, diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index ccf06b17bd..7e914bdc9b 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -164,7 +164,10 @@ const routes = ( /> } /> - } /> + } + /> } diff --git a/packages/app/src/apis.ts b/packages/app/src/apis.ts index 0c2ccbad22..e39122337f 100644 --- a/packages/app/src/apis.ts +++ b/packages/app/src/apis.ts @@ -26,6 +26,9 @@ import { discoveryApiRef, } from '@backstage/core-plugin-api'; import { AuthProxyDiscoveryApi } from './AuthProxyDiscoveryApi'; +import { formDecoratorsApiRef } from '@backstage/plugin-scaffolder/alpha'; +import { DefaultScaffolderFormDecoratorsApi } from '@backstage/plugin-scaffolder/alpha'; +import { mockDecorator } from './components/scaffolder/decorators'; export const apis: AnyApiFactory[] = [ createApiFactory({ @@ -39,5 +42,14 @@ export const apis: AnyApiFactory[] = [ factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi), }), + createApiFactory({ + api: formDecoratorsApiRef, + deps: {}, + factory: () => + DefaultScaffolderFormDecoratorsApi.create({ + decorators: [mockDecorator], + }), + }), + ScmAuth.createDefaultApiFactory(), ]; diff --git a/packages/app/src/components/scaffolder/decorators.ts b/packages/app/src/components/scaffolder/decorators.ts new file mode 100644 index 0000000000..ffb78562f8 --- /dev/null +++ b/packages/app/src/components/scaffolder/decorators.ts @@ -0,0 +1,36 @@ +/* + * 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 { githubAuthApiRef } from '@backstage/core-plugin-api'; +import { createScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; + +export const mockDecorator = createScaffolderFormDecorator({ + id: 'mock-decorator', + schema: { + input: { + test: z => z.string(), + }, + }, + deps: { + githubApi: githubAuthApiRef, + }, + decorator: async ( + { setSecrets, setFormState, input: { test } }, + { githubApi: _githubApi }, + ) => { + setFormState(state => ({ ...state, test, mock: 'MOCK' })); + setSecrets(state => ({ ...state, GITHUB_TOKEN: 'MOCK_TOKEN' })); + }, +}); diff --git a/packages/app/src/components/search/SearchPage.tsx b/packages/app/src/components/search/SearchPage.tsx index fe96e506eb..5a520e9211 100644 --- a/packages/app/src/components/search/SearchPage.tsx +++ b/packages/app/src/components/search/SearchPage.tsx @@ -117,7 +117,7 @@ const SearchPage = () => { name="kind" values={['Component', 'Template']} /> - new MockLogger(), - }), - loggerServiceFactory, + mockServices.rootLifecycle.factory(), + mockServices.lifecycle.factory(), + mockServices.rootLogger.factory(), + mockServices.logger.factory(), ]; +function mkNoopFactory(ref: ServiceRef<{}, 'plugin'>) { + const fn = jest.fn().mockReturnValue({}); + return Object.assign( + fn, + createServiceFactory({ + service: ref, + deps: {}, + factory: fn, + }), + ); +} + const testPlugin = createBackendPlugin({ pluginId: 'test', register(reg) { @@ -166,6 +163,151 @@ describe('BackendInitializer', () => { expect(moduleInit).toHaveBeenCalled(); }); + it('should ignore services provided by feature loaders that have already been explicitly added', async () => { + const ref = createServiceRef<{}>({ id: '1' }); + const factory1 = mkNoopFactory(ref); + const factory2 = mkNoopFactory(ref); + const factory3 = mkNoopFactory(ref); + + const init = new BackendInitializer([...baseFactories, factory1]); + init.add(factory2); + init.add( + createBackendFeatureLoader({ + deps: {}, + *loader() { + yield factory3; + }, + }), + ); + init.add( + createBackendPlugin({ + pluginId: 'tester', + register(reg) { + reg.registerInit({ + deps: { ref }, + async init() {}, + }); + }, + }), + ); + + await init.start(); + + expect(factory1).not.toHaveBeenCalled(); + expect(factory2).toHaveBeenCalled(); + expect(factory3).not.toHaveBeenCalled(); + }); + + it('should include all multiton service factories', async () => { + expect.assertions(5); + + const ref = createServiceRef({ id: '1', multiton: true }); + const factory1 = mkNoopFactory(ref).mockResolvedValue(1); + const factory2 = mkNoopFactory(ref).mockResolvedValue(2); + const factory3 = mkNoopFactory(ref).mockResolvedValue(3); + const factory4 = mkNoopFactory(ref).mockResolvedValue(4); + + const init = new BackendInitializer([...baseFactories, factory1]); + init.add(factory2); + init.add( + createBackendFeatureLoader({ + deps: {}, + *loader() { + yield factory3; + yield factory4; + }, + }), + ); + init.add( + createBackendPlugin({ + pluginId: 'tester', + register(reg) { + reg.registerInit({ + deps: { ns: ref }, + async init({ ns }) { + expect(ns).toEqual([1, 2, 3, 4]); + }, + }); + }, + }), + ); + + await init.start(); + + expect(factory1).toHaveBeenCalled(); + expect(factory2).toHaveBeenCalled(); + expect(factory3).toHaveBeenCalled(); + expect(factory4).toHaveBeenCalled(); + }); + + // Note: this is an important escape hatch in case to loaders conflict and you need to select the winning service factory + it('should allow duplicate service from feature loaders if overridden', async () => { + const ref = createServiceRef<{}>({ id: '1' }); + const factory1 = mkNoopFactory(ref); + const factory2 = mkNoopFactory(ref); + const factory3 = mkNoopFactory(ref); + const factory4 = mkNoopFactory(ref); + + const init = new BackendInitializer([...baseFactories, factory1]); + init.add(factory2); + init.add( + createBackendFeatureLoader({ + deps: {}, + *loader() { + yield factory3; + yield factory4; + }, + }), + ); + init.add( + createBackendPlugin({ + pluginId: 'tester', + register(reg) { + reg.registerInit({ + deps: { ref }, + async init() {}, + }); + }, + }), + ); + + await init.start(); + + expect(factory1).not.toHaveBeenCalled(); + expect(factory2).toHaveBeenCalled(); + expect(factory3).not.toHaveBeenCalled(); + expect(factory4).not.toHaveBeenCalled(); + }); + + it('should reject duplicate service factories from feature loader without an explicit override', async () => { + const ref = createServiceRef<{}>({ id: '1' }); + const factory1 = mkNoopFactory(ref); + const factory2 = mkNoopFactory(ref); + const factory3 = mkNoopFactory(ref); + + const init = new BackendInitializer([...baseFactories, factory1]); + init.add( + createBackendFeatureLoader({ + deps: {}, + *loader() { + yield factory2; + }, + }), + ); + init.add( + createBackendFeatureLoader({ + deps: {}, + *loader() { + yield factory3; + }, + }), + ); + + await expect(init.start()).rejects.toThrow( + 'Duplicate service implementations provided for 1 by both feature loader created at', + ); + }); + it('should refuse to override already initialized services through loaded features', async () => { const ref1 = createServiceRef<{ x: number }>({ id: '1', @@ -548,12 +690,8 @@ describe('BackendInitializer', () => { const extA = createExtensionPoint({ id: 'a' }); const extB = createExtensionPoint({ id: 'b' }); const init = new BackendInitializer([ - rootLifecycleServiceFactory, - createServiceFactory({ - service: coreServices.rootLogger, - deps: {}, - factory: () => new MockLogger(), - }), + mockServices.rootLifecycle.factory(), + mockServices.rootLogger.factory(), ]); init.add(testPlugin); init.add( @@ -724,4 +862,66 @@ describe('BackendInitializer', () => { await init.start(); }); + + it('should properly add plugins + modules to the instance metadata service', async () => { + expect.assertions(2); + const backend = new BackendInitializer(baseFactories); + const plugin = createBackendPlugin({ + pluginId: 'test', + register(reg) { + reg.registerInit({ + deps: {}, + async init() {}, + }); + }, + }); + const instanceMetadataPlugin = createBackendPlugin({ + pluginId: 'instance-metadata', + register(reg) { + reg.registerInit({ + deps: { + instanceMetadata: instanceMetadataServiceRef, + }, + async init({ instanceMetadata }) { + expect(instanceMetadata.getInstalledFeatures()).toEqual([ + { + pluginId: 'test', + type: 'plugin', + }, + { + pluginId: 'test', + moduleId: 'test', + type: 'module', + }, + { + pluginId: 'instance-metadata', + type: 'plugin', + }, + ]); + expect(instanceMetadata.getInstalledFeatures().map(String)).toEqual( + [ + 'plugin{pluginId=test}', + 'module{moduleId=test,pluginId=test}', + 'plugin{pluginId=instance-metadata}', + ], + ); + }, + }); + }, + }); + const module = createBackendModule({ + pluginId: 'test', + moduleId: 'test', + register(reg) { + reg.registerInit({ + deps: {}, + async init() {}, + }); + }, + }); + backend.add(plugin); + backend.add(module); + backend.add(instanceMetadataPlugin); + await backend.start(); + }); }); diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 3ea1200898..aa48c26877 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -22,6 +22,7 @@ import { ServiceFactory, LifecycleService, RootLifecycleService, + createServiceFactory, } from '@backstage/backend-plugin-api'; import { ServiceOrExtensionPoint } from './types'; // Direct internal import to avoid duplication @@ -34,7 +35,11 @@ import type { // eslint-disable-next-line @backstage/no-relative-monorepo-imports import type { InternalServiceFactory } from '../../../backend-plugin-api/src/services/system/types'; import { ForwardedError, ConflictError } from '@backstage/errors'; -import { featureDiscoveryServiceRef } from '@backstage/backend-plugin-api/alpha'; +import { + instanceMetadataServiceRef, + featureDiscoveryServiceRef, + BackendFeatureMeta, +} from '@backstage/backend-plugin-api/alpha'; import { DependencyGraph } from '../lib/DependencyGraph'; import { ServiceRegistry } from './ServiceRegistry'; import { createInitializationLogger } from './createInitializationLogger'; @@ -96,6 +101,59 @@ const instanceRegistry = new (class InstanceRegistry { }; })(); +function createInstanceMetadataServiceFactory( + registrations: InternalBackendRegistrations[], +) { + const installedFeatures = registrations + .map(registration => { + if (registration.featureType === 'registrations') { + return registration + .getRegistrations() + .map(feature => { + if (feature.type === 'plugin') { + return Object.defineProperty( + { + type: 'plugin', + pluginId: feature.pluginId, + }, + 'toString', + { + enumerable: false, + configurable: true, + value: () => `plugin{pluginId=${feature.pluginId}}`, + }, + ); + } else if (feature.type === 'module') { + return Object.defineProperty( + { + type: 'module', + pluginId: feature.pluginId, + moduleId: feature.moduleId, + }, + 'toString', + { + enumerable: false, + configurable: true, + value: () => + `module{moduleId=${feature.moduleId},pluginId=${feature.pluginId}}`, + }, + ); + } + // Ignore unknown feature types. + return undefined; + }) + .filter(Boolean) as BackendFeatureMeta[]; + } + return []; + }) + .flat(); + return createServiceFactory({ + service: instanceMetadataServiceRef, + deps: {}, + factory: async () => ({ getInstalledFeatures: () => installedFeatures }), + }); +} + export class BackendInitializer { #startPromise?: Promise; #stopPromise?: Promise; @@ -210,6 +268,10 @@ export class BackendInitializer { await this.#applyBackendFeatureLoaders(this.#registeredFeatureLoaders); + this.#serviceRegistry.add( + createInstanceMetadataServiceFactory(this.#registrations), + ); + // Initialize all root scoped services await this.#serviceRegistry.initializeEagerServicesWithScope('root'); @@ -407,6 +469,11 @@ export class BackendInitializer { // The startup failed, but we may still want to do cleanup so we continue silently } + const rootLifecycleService = await this.#getRootLifecycleImpl(); + + // Root services like the health one need to immediatelly be notified of the shutdown + await rootLifecycleService.beforeShutdown(); + // Get all plugins. const allPlugins = new Set(); for (const feature of this.#registrations) { @@ -426,14 +493,14 @@ export class BackendInitializer { ); // Once all plugin shutdown hooks are done, run root shutdown hooks. - const lifecycleService = await this.#getRootLifecycleImpl(); - await lifecycleService.shutdown(); + await rootLifecycleService.shutdown(); } // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this async #getRootLifecycleImpl(): Promise< RootLifecycleService & { startup(): Promise; + beforeShutdown(): Promise; shutdown(): Promise; } > { @@ -477,6 +544,11 @@ export class BackendInitializer { } async #applyBackendFeatureLoaders(loaders: InternalBackendFeatureLoader[]) { + const servicesAddedByLoaders = new Map< + string, + InternalBackendFeatureLoader + >(); + for (const loader of loaders) { const deps = new Map(); const missingRefs = new Set(); @@ -522,8 +594,32 @@ export class BackendInitializer { if (isBackendFeatureLoader(feature)) { newLoaders.push(feature); } else { - didAddServiceFactory ||= isServiceFactory(feature); - this.#addFeature(feature); + // This block makes sure that feature loaders do not provide duplicate + // implementations for the same service, but at the same time allows + // service factories provided by feature loaders to be overridden by + // ones that are explicitly installed with backend.add(serviceFactory). + // + // If a factory has already been explicitly installed, the service + // factory provided by the loader will simply be ignored. + if (isServiceFactory(feature) && !feature.service.multiton) { + const conflictingLoader = servicesAddedByLoaders.get( + feature.service.id, + ); + if (conflictingLoader) { + throw new Error( + `Duplicate service implementations provided for ${feature.service.id} by both feature loader ${loader.description} and feature loader ${conflictingLoader.description}`, + ); + } + + // Check that this service wasn't already explicitly added by backend.add(serviceFactory) + if (!this.#serviceRegistry.hasBeenAdded(feature.service)) { + didAddServiceFactory = true; + servicesAddedByLoaders.set(feature.service.id, loader); + this.#addFeature(feature); + } + } else { + this.#addFeature(feature); + } } } diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 0abd5605ae..90b108206e 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -191,6 +191,13 @@ export class ServiceRegistry { } } + hasBeenAdded(ref: ServiceRef) { + if (ref.id === coreServices.pluginMetadata.id) { + return true; + } + return this.#addedFactoryIds.has(ref.id); + } + add(factory: ServiceFactory) { const factoryId = factory.service.id; if (factoryId === coreServices.pluginMetadata.id) { diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts index 1fd7fcbbec..32c1fbcd0e 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts @@ -36,6 +36,7 @@ describe('createSpecializedBackend', () => { deps: {}, factory: async () => ({ addStartupHook: () => {}, + addBeforeShutdownHook: () => {}, addShutdownHook: () => {}, }), }), @@ -44,6 +45,7 @@ describe('createSpecializedBackend', () => { deps: {}, factory: async () => ({ addStartupHook: () => {}, + addBeforeShutdownHook: () => {}, addShutdownHook: () => {}, }), }), diff --git a/packages/backend-defaults/CHANGELOG.md b/packages/backend-defaults/CHANGELOG.md index 1f64b8f4c9..4d3cb90097 100644 --- a/packages/backend-defaults/CHANGELOG.md +++ b/packages/backend-defaults/CHANGELOG.md @@ -1,5 +1,132 @@ # @backstage/backend-defaults +## 0.6.0-next.2 + +### Minor Changes + +- fd5d337: Added a new `backend.health.headers` configuration that can be used to set additional headers to include in health check responses. + + **BREAKING CONSUMERS**: As part of this change the `createHealthRouter` function exported from `@backstage/backend-defaults/rootHttpRouter` now requires the root config service to be passed through the `config` option. + +- 3f34ea9: Throttles Bitbucket Server API calls + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 57e0b11: The user and plugin token verification in the default `AuthService` implementation will no longer forward verification errors to the caller, and instead log them as warnings. +- 57e0b11: The default `authServiceFactory` now correctly depends on the plugin scoped `Logger` services rather than the root scoped one. +- 0e9c9fa: Implements the `DefaultRootLifecycleService.addBeforeShutdownHook` method, and updates `DefaultRootHttpRouterService` and `DefaultRootHealthService` to listen to that event to stop accepting traffic and close service connections. +- d0cbd82: Remove use of the `stoppable` library on the `DefaultRootHttpRouterService` as Node's native http server [close](https://nodejs.org/api/http.html#serverclosecallback) method already drains requests. + Also, we pass a new `lifecycleMiddleware` to the `rootHttpRouterServiceFactory` configure function that must be called manually if you don't call `applyDefaults`. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + +## 0.6.0-next.1 + +### Patch Changes + +- fe87fbf: Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. +- 1ac6b72: Support `connection.type: cloudsql` in database client for usage with `@google-cloud/cloud-sql-connector` and `iam` auth +- 5c9cc05: Use native fetch instead of node-fetch +- cf627c6: Fixed an issue in the WinstonLogger where Errors thrown and given to logger.error with field values that could not be cast to a string would throw a TypeError +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.6.0-next.0 + +### Minor Changes + +- de6f280: **BREAKING** Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys. + + This is a breaking change for clients using the `redis` store for cache with `useRedisSets` option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore. + + If you were using `useRedisSets` option in configuration make sure to remove it from `app-config.yaml`: + + ```diff + backend: + cache: + store: redis + connection: redis://user:pass@cache.example.com:6379 + - useRedisSets: false + ``` + +- 277092a: Implemented `AzureBlobStorageUrlReader` to read from the url of committed location from the entity provider +- 18a2c00: All middleware used by the default `coreServices.http` is now exported for use by custom implementations. + +### Patch Changes + +- 8863b38: Export `PluginTokenHandler` and `pluginTokenHandlerDecoratorServiceRef` to allow for custom decoration of the plugin token handler without having to re-implement the entire handler. +- 97c6837: Export `DefaultHttpAuthService` to allow for custom token extraction logic. +- e5255f1: Log request and response metadata so it can be used for filtering log messages. + The format of the request date was also changed from `clf` to `utc`. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 0.5.3 + +### Patch Changes + +- bf306cb: Removed dependency `@backstage/backend-common`. +- e30bb46: Disabling database migrations now correctly uses the `backend.default.skipMigrations` config value. +- d52d7f9: Support ISO and ms string forms of durations in config too +- f6eaec2: Link to proper package in `rootLoggerServiceFactory` doc string. +- ecf6b39: Use `node-fetch` instead of native fetch, as per https://backstage.io/docs/architecture-decisions/adrs-adr013 +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/backend-dev-utils@0.1.5 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-permission-node@0.8.5 + ## 0.5.3-next.3 ### Patch Changes diff --git a/packages/backend-defaults/config.d.ts b/packages/backend-defaults/config.d.ts index a8c6e1c290..e2a748f85d 100644 --- a/packages/backend-defaults/config.d.ts +++ b/packages/backend-defaults/config.d.ts @@ -28,6 +28,29 @@ export interface Config { */ baseUrl: string; + lifecycle?: { + /** + * The maximum time that paused requests will wait for the service to start, before returning an error. + * Defaults to 5 seconds + * Supported formats: + * - 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 }`. + */ + startupRequestPauseTimeout?: string | HumanDuration; + /** + * The minimum time that the HTTP server will delay the shutdown of the backend. During this delay health checks will be set to failing, allowing traffic to drain. + * Defaults to 0 seconds. + * Supported formats: + * - 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 }`. + */ + serverShutdownDelay?: string | HumanDuration; + }; + /** Address that the backend should listen to. */ listen?: | string @@ -384,6 +407,16 @@ export interface Config { */ connection: | string + | { + /** + * The specific config for cloudsql connections + */ + type: 'cloudsql'; + /** + * The instance connection name for the cloudsql instance, e.g. `project:region:instance` + */ + instance: string; + } | { /** * Password that belongs to the client User @@ -441,7 +474,30 @@ export interface Config { * Database connection string or Knex object override * @visibility secret */ - connection?: string | object; + connection?: + | string + | { + /** + * The specific config for cloudsql connections + */ + type: 'cloudsql'; + /** + * The instance connection name for the cloudsql instance, e.g. `project:region:instance` + */ + instance: string; + } + | { + /** + * Password that belongs to the client User + * @visibility secret + */ + password?: string; + /** + * Other connection settings + */ + [key: string]: unknown; + }; + /** * Whether to ensure the given database exists by creating it if it does not. * Defaults to base config if unspecified. @@ -474,8 +530,8 @@ export interface Config { cache?: | { store: 'memory'; - /** An optional default TTL (in milliseconds). */ - defaultTtl?: number | HumanDuration; + /** An optional default TTL (in milliseconds, if given as a number). */ + defaultTtl?: number | HumanDuration | string; } | { store: 'redis'; @@ -484,13 +540,8 @@ export interface Config { * @visibility secret */ connection: string; - /** An optional default TTL (in milliseconds). */ - defaultTtl?: number | HumanDuration; - /** - * Whether or not [useRedisSets](https://github.com/jaredwray/keyv/tree/main/packages/redis#useredissets) should be configured to this redis cache. - * Defaults to true if unspecified. - */ - useRedisSets?: boolean; + /** An optional default TTL (in milliseconds, if given as a number). */ + defaultTtl?: number | HumanDuration | string; } | { store: 'memcache'; @@ -500,7 +551,7 @@ export interface Config { */ connection: string; /** An optional default TTL (in milliseconds). */ - defaultTtl?: number | HumanDuration; + defaultTtl?: number | HumanDuration | string; }; cors?: { @@ -524,6 +575,23 @@ export interface Config { */ csp?: { [policyId: string]: string[] | false }; + /** + * Options for the health check service and endpoint. + */ + health?: { + /** + * Additional headers to always include in the health check response. + * + * It can be a good idea to set a header that uniquely identifies your service + * in a multi-service environment. This ensures that the health check that is + * configured for your service is actually hitting your service and not another. + * + * For example, if using Envoy you can use the `service_name_matcher` configuration + * and set the `x-envoy-upstream-healthchecked-cluster` header to a matching value. + */ + headers?: { [name: string]: string }; + }; + /** * 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 6aa4c06aee..c384833c55 100644 --- a/packages/backend-defaults/package.json +++ b/packages/backend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/backend-defaults", - "version": "0.5.3-next.3", + "version": "0.6.0-next.2", "description": "Backend defaults used by Backstage backend apps", "backstage": { "role": "node-library" @@ -119,8 +119,9 @@ "@aws-sdk/client-s3": "^3.350.0", "@aws-sdk/credential-providers": "^3.350.0", "@aws-sdk/types": "^3.347.0", + "@azure/identity": "^4.0.0", + "@azure/storage-blob": "^12.5.0", "@backstage/backend-app-api": "workspace:^", - "@backstage/backend-common": "^0.25.0", "@backstage/backend-dev-utils": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/cli-common": "workspace:^", @@ -135,11 +136,11 @@ "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^", "@google-cloud/storage": "^7.0.0", - "@keyv/memcache": "^1.3.5", - "@keyv/redis": "^2.5.3", + "@keyv/memcache": "^2.0.1", + "@keyv/redis": "^4.0.1", "@manypkg/get-packages": "^1.1.3", "@octokit/rest": "^19.0.3", - "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api": "^1.9.0", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "archiver": "^7.0.0", @@ -157,25 +158,24 @@ "helmet": "^6.0.0", "isomorphic-git": "^1.23.0", "jose": "^5.0.0", - "keyv": "^4.5.2", + "keyv": "^5.2.1", "knex": "^3.0.0", "lodash": "^4.17.21", "logform": "^2.3.2", "luxon": "^3.0.0", "minimatch": "^9.0.0", "minimist": "^1.2.5", - "morgan": "^1.10.0", "mysql2": "^3.0.0", "node-fetch": "^2.7.0", "node-forge": "^1.3.1", "p-limit": "^3.1.0", + "p-throttle": "^4.1.1", "path-to-regexp": "^8.0.0", "pg": "^8.11.3", "pg-connection-string": "^2.3.0", "pg-format": "^1.0.4", "raw-body": "^2.4.1", "selfsigned": "^2.0.0", - "stoppable": "^1.1.0", "tar": "^6.1.12", "triple-beam": "^1.4.1", "uuid": "^11.0.0", @@ -185,16 +185,24 @@ "yn": "^4.0.0", "zod": "^3.22.4" }, + "peerDependencies": { + "@google-cloud/cloud-sql-connector": "^1.4.0" + }, + "peerDependenciesMeta": { + "@google-cloud/cloud-sql-connector": { + "optional": true + } + }, "devDependencies": { "@aws-sdk/util-stream-node": "^3.350.0", "@backstage/backend-plugin-api": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", + "@google-cloud/cloud-sql-connector": "^1.4.0", "@types/archiver": "^6.0.0", "@types/base64-stream": "^1.0.2", "@types/concat-stream": "^2.0.0", "@types/http-errors": "^2.0.0", - "@types/morgan": "^1.9.0", "@types/node-forge": "^1.3.0", "@types/pg-format": "^1.0.5", "@types/stoppable": "^1.1.0", @@ -202,6 +210,7 @@ "aws-sdk-client-mock": "^4.0.0", "http-errors": "^2.0.0", "msw": "^1.0.0", + "node-mocks-http": "^1.0.0", "supertest": "^7.0.0", "wait-for-expect": "^3.0.2" }, diff --git a/packages/backend-defaults/report-auth.api.md b/packages/backend-defaults/report-auth.api.md index 2f201e4573..1883e65a6a 100644 --- a/packages/backend-defaults/report-auth.api.md +++ b/packages/backend-defaults/report-auth.api.md @@ -5,6 +5,7 @@ ```ts import { AuthService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceRef } from '@backstage/backend-plugin-api'; // @public export const authServiceFactory: ServiceFactory< @@ -13,5 +14,35 @@ export const authServiceFactory: ServiceFactory< 'singleton' >; +// @public +export interface PluginTokenHandler { + // (undocumented) + issueToken(options: { + pluginId: string; + targetPluginId: string; + onBehalfOf?: { + limitedUserToken: string; + expiresAt: Date; + }; + }): Promise<{ + token: string; + }>; + // (undocumented) + verifyToken(token: string): Promise< + | { + subject: string; + limitedUserToken?: string; + } + | undefined + >; +} + +// @public +export const pluginTokenHandlerDecoratorServiceRef: ServiceRef< + (defaultImplementation: PluginTokenHandler) => PluginTokenHandler, + 'plugin', + 'singleton' +>; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/report-httpAuth.api.md b/packages/backend-defaults/report-httpAuth.api.md index 6c08a6f4d0..b3843beb3d 100644 --- a/packages/backend-defaults/report-httpAuth.api.md +++ b/packages/backend-defaults/report-httpAuth.api.md @@ -3,9 +3,51 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AuthService } from '@backstage/backend-plugin-api'; +import { BackstageCredentials } from '@backstage/backend-plugin-api'; +import { BackstagePrincipalTypes } from '@backstage/backend-plugin-api'; +import { DiscoveryService } from '@backstage/backend-plugin-api'; import { HttpAuthService } from '@backstage/backend-plugin-api'; +import { Request as Request_2 } from 'express'; +import { Response as Response_2 } from 'express'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +// @public +export class DefaultHttpAuthService implements HttpAuthService { + // (undocumented) + static create(options: DefaultHttpAuthServiceOptions): DefaultHttpAuthService; + // (undocumented) + credentials( + req: Request_2, + options?: { + allow?: Array; + allowLimitedAccess?: boolean; + }, + ): Promise>; + // (undocumented) + issueUserCookie( + res: Response_2, + options?: { + credentials?: BackstageCredentials; + }, + ): Promise<{ + expiresAt: Date; + }>; +} + +// @public +export interface DefaultHttpAuthServiceOptions { + // (undocumented) + auth: AuthService; + // (undocumented) + discovery: DiscoveryService; + getTokenFromRequest?: (req: Request_2) => { + token?: string; + }; + // (undocumented) + pluginId: string; +} + // @public export const httpAuthServiceFactory: ServiceFactory< HttpAuthService, diff --git a/packages/backend-defaults/report-httpRouter.api.md b/packages/backend-defaults/report-httpRouter.api.md index 97805bc926..55c3f0b208 100644 --- a/packages/backend-defaults/report-httpRouter.api.md +++ b/packages/backend-defaults/report-httpRouter.api.md @@ -3,9 +3,44 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +/// + +import { AuthService } from '@backstage/backend-plugin-api'; +import express from 'express'; +import { HttpAuthService } from '@backstage/backend-plugin-api'; import { HttpRouterService } from '@backstage/backend-plugin-api'; +import { HttpRouterServiceAuthPolicy } from '@backstage/backend-plugin-api'; +import { LifecycleService } from '@backstage/backend-plugin-api'; +import { RequestHandler } from 'express'; +import { RootConfigService } from '@backstage/backend-plugin-api'; +import { Router } from 'express'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +// @public (undocumented) +export function createAuthIntegrationRouter(options: { + auth: AuthService; +}): express.Router; + +// @public +export function createCookieAuthRefreshMiddleware(options: { + auth: AuthService; + httpAuth: HttpAuthService; +}): Router; + +// @public (undocumented) +export function createCredentialsBarrier(options: { + httpAuth: HttpAuthService; + config: RootConfigService; +}): { + middleware: RequestHandler; + addAuthPolicy: (policy: HttpRouterServiceAuthPolicy) => void; +}; + +// @public +export function createLifecycleMiddleware( + options: LifecycleMiddlewareOptions, +): RequestHandler; + // @public export const httpRouterServiceFactory: ServiceFactory< HttpRouterService, @@ -13,5 +48,13 @@ export const httpRouterServiceFactory: ServiceFactory< 'singleton' >; +// @public +export interface LifecycleMiddlewareOptions { + // (undocumented) + config: RootConfigService; + // (undocumented) + lifecycle: LifecycleService; +} + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-defaults/report-rootHttpRouter.api.md b/packages/backend-defaults/report-rootHttpRouter.api.md index 3686f25a12..41830ebf17 100644 --- a/packages/backend-defaults/report-rootHttpRouter.api.md +++ b/packages/backend-defaults/report-rootHttpRouter.api.md @@ -27,6 +27,7 @@ import { ServiceFactory } from '@backstage/backend-plugin-api'; // @public (undocumented) export function createHealthRouter(options: { health: RootHealthService; + config: RootConfigService; }): Router; // @public diff --git a/packages/backend-defaults/report-urlReader.api.md b/packages/backend-defaults/report-urlReader.api.md index f8b8db2954..efe4a9ae47 100644 --- a/packages/backend-defaults/report-urlReader.api.md +++ b/packages/backend-defaults/report-urlReader.api.md @@ -7,6 +7,8 @@ import { AwsCredentialsManager } from '@backstage/integration-aws-node'; import { AwsS3Integration } from '@backstage/integration'; +import { AzureBlobStorageIntergation } from '@backstage/integration'; +import { AzureCredentialsManager } from '@backstage/integration'; import { AzureDevOpsCredentialsProvider } from '@backstage/integration'; import { AzureIntegration } from '@backstage/integration'; import { BitbucketCloudIntegration } from '@backstage/integration'; @@ -60,6 +62,35 @@ export class AwsS3UrlReader implements UrlReaderService { toString(): string; } +// @public +export class AzureBlobStorageUrlReader implements UrlReaderService { + constructor( + credsManager: AzureCredentialsManager, + integration: AzureBlobStorageIntergation, + deps: { + treeResponseFactory: ReadTreeResponseFactory; + }, + ); + // (undocumented) + static factory: ReaderFactory; + // (undocumented) + read(url: string): Promise; + // (undocumented) + readTree( + url: string, + options?: UrlReaderServiceReadTreeOptions, + ): Promise; + // (undocumented) + readUrl( + url: string, + options?: UrlReaderServiceReadUrlOptions, + ): Promise; + // (undocumented) + search(): Promise; + // (undocumented) + toString(): string; +} + // @public export class AzureUrlReader implements UrlReaderService { constructor( @@ -384,17 +415,29 @@ export interface ReadTreeResponseFactory { } // @public -export type ReadTreeResponseFactoryOptions = { - stream: Readable; - subpath?: string; - etag: string; - filter?: ( - path: string, - info?: { - size: number; - }, - ) => boolean; -}; +export type ReadTreeResponseFactoryOptions = + | { + stream: Readable; + subpath?: string; + etag: string; + filter?: ( + path: string, + info?: { + size: number; + }, + ) => boolean; + } + | { + response: Response; + subpath?: string; + etag?: string; + filter?: ( + path: string, + info?: { + size: number; + }, + ) => boolean; + }; // @public export class ReadUrlResponseFactory { @@ -406,6 +449,9 @@ export class ReadUrlResponseFactory { stream: Readable, options?: ReadUrlResponseFactoryFromStreamOptions, ): Promise; + static fromResponse( + response: Response, + ): Promise; } // @public diff --git a/packages/backend-defaults/src/CreateBackend.test.ts b/packages/backend-defaults/src/CreateBackend.test.ts index 55fdbe5a6a..57977e9647 100644 --- a/packages/backend-defaults/src/CreateBackend.test.ts +++ b/packages/backend-defaults/src/CreateBackend.test.ts @@ -47,6 +47,7 @@ describe('createBackend', () => { deps: {}, factory: async () => ({ addStartupHook: () => {}, + addBeforeShutdownHook: () => {}, addShutdownHook: () => {}, }), }), @@ -57,6 +58,7 @@ describe('createBackend', () => { deps: {}, factory: async () => ({ addStartupHook: () => {}, + addBeforeShutdownHook: () => {}, addShutdownHook: () => {}, }), }), diff --git a/packages/backend-defaults/src/entrypoints/auth/DefaultAuthService.ts b/packages/backend-defaults/src/entrypoints/auth/DefaultAuthService.ts index 05d62a54a2..a81a99fec7 100644 --- a/packages/backend-defaults/src/entrypoints/auth/DefaultAuthService.ts +++ b/packages/backend-defaults/src/entrypoints/auth/DefaultAuthService.ts @@ -169,7 +169,10 @@ export class DefaultAuthService implements AuthService { return this.pluginTokenHandler.issueToken({ pluginId: this.pluginId, targetPluginId, - onBehalfOf, + onBehalfOf: { + limitedUserToken: onBehalfOf.token, + expiresAt: onBehalfOf.expiresAt, + }, }); } default: diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts index cb672ed7f1..a244614135 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.test.ts @@ -19,12 +19,17 @@ import { mockServices, registerMswTestHooks, } from '@backstage/backend-test-utils'; -import { authServiceFactory } from './authServiceFactory'; +import { + authServiceFactory, + pluginTokenHandlerDecoratorServiceRef, +} from './authServiceFactory'; import { base64url, decodeJwt } from 'jose'; import { discoveryServiceFactory } from '../discovery'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { toInternalBackstageCredentials } from './helpers'; +import { PluginTokenHandler } from './plugin/PluginTokenHandler'; +import { createServiceFactory } from '@backstage/backend-plugin-api'; const server = setupServer(); @@ -104,8 +109,9 @@ describe('authServiceFactory', () => { }); it('should authenticate issued tokens with new auth', async () => { + const logger = mockServices.logger.mock(); const tester = ServiceFactoryTester.from(authServiceFactory, { - dependencies: mockDeps, + dependencies: [...mockDeps, logger.factory], }); const searchAuth = await tester.getSubject('search'); @@ -129,8 +135,13 @@ describe('authServiceFactory', () => { targetPluginId: 'catalog', }); + expect(logger.warn).not.toHaveBeenCalled(); await expect(searchAuth.authenticate(searchToken)).rejects.toThrow( - 'Invalid plugin token', + 'Failed plugin token verification', + ); + expect(logger.warn).toHaveBeenCalledWith( + 'Failed to verify incoming plugin token', + expect.any(Error), ); await expect(catalogAuth.authenticate(searchToken)).resolves.toEqual( expect.objectContaining({ @@ -407,4 +418,40 @@ describe('authServiceFactory', () => { principal: { subject: 'unlimited-static-subject' }, }); }); + + describe('decorate PluginTokenHandler', () => { + it('should allow custom logic to be injected into the plugin token handler', async () => { + const customLogic = jest.fn(); + const customPluginTokenHandler = createServiceFactory({ + service: pluginTokenHandlerDecoratorServiceRef, + deps: {}, + async factory() { + return (defaultImplementation: PluginTokenHandler) => + new (class CustomHandler implements PluginTokenHandler { + verifyToken( + token: string, + ): Promise< + { subject: string; limitedUserToken?: string } | undefined + > { + customLogic(token); + return defaultImplementation.verifyToken(token); + } + issueToken(options: { + pluginId: string; + targetPluginId: string; + limitedUserToken?: { token: string; expiresAt: Date }; + }): Promise<{ token: string }> { + return defaultImplementation.issueToken(options); + } + })(); + }, + }); + const tester = ServiceFactoryTester.from(authServiceFactory, { + dependencies: [...mockDeps, customPluginTokenHandler], + }); + const searchAuth = await tester.getSubject('search'); + searchAuth.authenticate('unlimited-static-token'); + expect(customLogic).toHaveBeenCalledWith('unlimited-static-token'); + }); + }); }); diff --git a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.ts b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.ts index 34071ca541..91910292e6 100644 --- a/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/auth/authServiceFactory.ts @@ -17,13 +17,35 @@ import { coreServices, createServiceFactory, + createServiceRef, } from '@backstage/backend-plugin-api'; import { DefaultAuthService } from './DefaultAuthService'; import { ExternalTokenHandler } from './external/ExternalTokenHandler'; -import { PluginTokenHandler } from './plugin/PluginTokenHandler'; +import { + DefaultPluginTokenHandler, + PluginTokenHandler, +} from './plugin/PluginTokenHandler'; import { createPluginKeySource } from './plugin/keys/createPluginKeySource'; import { UserTokenHandler } from './user/UserTokenHandler'; +/** + * @public + * This service is used to decorate the default plugin token handler with custom logic. + */ +export const pluginTokenHandlerDecoratorServiceRef = createServiceRef< + (defaultImplementation: PluginTokenHandler) => PluginTokenHandler +>({ + id: 'core.auth.pluginTokenHandlerDecorator', + defaultFactory: async service => + createServiceFactory({ + service, + deps: {}, + factory: async () => { + return impl => impl; + }, + }), +}); + /** * Handles token authentication and credentials management. * @@ -37,12 +59,20 @@ export const authServiceFactory = createServiceFactory({ service: coreServices.auth, deps: { config: coreServices.rootConfig, - logger: coreServices.rootLogger, + logger: coreServices.logger, discovery: coreServices.discovery, plugin: coreServices.pluginMetadata, database: coreServices.database, + pluginTokenHandlerDecorator: pluginTokenHandlerDecoratorServiceRef, }, - async factory({ config, discovery, plugin, logger, database }) { + async factory({ + config, + discovery, + plugin, + logger, + database, + pluginTokenHandlerDecorator, + }) { const disableDefaultAuthPolicy = config.getOptionalBoolean( 'backend.auth.dangerouslyDisableDefaultAuthPolicy', @@ -59,15 +89,18 @@ export const authServiceFactory = createServiceFactory({ const userTokens = UserTokenHandler.create({ discovery, + logger, }); - const pluginTokens = PluginTokenHandler.create({ - ownPluginId: plugin.getId(), - logger, - keySource, - keyDuration, - discovery, - }); + const pluginTokens = pluginTokenHandlerDecorator( + DefaultPluginTokenHandler.create({ + ownPluginId: plugin.getId(), + logger, + keySource, + keyDuration, + discovery, + }), + ); const externalTokens = ExternalTokenHandler.create({ ownPluginId: plugin.getId(), diff --git a/packages/backend-defaults/src/entrypoints/auth/index.ts b/packages/backend-defaults/src/entrypoints/auth/index.ts index 1b55d46a83..e48926f0ce 100644 --- a/packages/backend-defaults/src/entrypoints/auth/index.ts +++ b/packages/backend-defaults/src/entrypoints/auth/index.ts @@ -14,4 +14,9 @@ * limitations under the License. */ -export { authServiceFactory } from './authServiceFactory'; +export { + authServiceFactory, + pluginTokenHandlerDecoratorServiceRef, +} from './authServiceFactory'; + +export type { PluginTokenHandler } from './plugin/PluginTokenHandler'; diff --git a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.test.ts index ce470eff04..558bc5d0da 100644 --- a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.test.ts @@ -15,7 +15,7 @@ */ import { mockServices } from '@backstage/backend-test-utils'; -import { PluginTokenHandler } from './PluginTokenHandler'; +import { DefaultPluginTokenHandler } from './PluginTokenHandler'; import { decodeJwt } from 'jose'; describe('PluginTokenHandler', () => { @@ -42,7 +42,7 @@ describe('PluginTokenHandler', () => { }); const getKeyMock = jest.fn(async () => mockPrivateKey); - const handler = PluginTokenHandler.create({ + const handler = DefaultPluginTokenHandler.create({ discovery: mockServices.discovery(), keyDuration: { seconds: 10 }, logger: mockServices.logger.mock(), diff --git a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts index 4bea74e3af..9aec52bc08 100644 --- a/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts +++ b/packages/backend-defaults/src/entrypoints/auth/plugin/PluginTokenHandler.ts @@ -16,13 +16,12 @@ import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api'; import { decodeJwt, importJWK, SignJWT, decodeProtectedHeader } from 'jose'; -import { AuthenticationError } from '@backstage/errors'; +import { assertError, AuthenticationError } from '@backstage/errors'; import { jwtVerify } from 'jose'; import { tokenTypes } from '@backstage/plugin-auth-node'; import { JwksClient } from '../JwksClient'; import { HumanDuration, durationToMilliseconds } from '@backstage/types'; import { PluginKeySource } from './keys/types'; -import fetch from 'node-fetch'; const SECONDS_IN_MS = 1000; @@ -45,7 +44,22 @@ type Options = { algorithm?: string; }; -export class PluginTokenHandler { +/** + * @public + * Issues and verifies {@link https://backstage.iceio/docs/auth/service-to-service-auth | service-to-service tokens}. + */ +export interface PluginTokenHandler { + verifyToken( + token: string, + ): Promise<{ subject: string; limitedUserToken?: string } | undefined>; + issueToken(options: { + pluginId: string; + targetPluginId: string; + onBehalfOf?: { limitedUserToken: string; expiresAt: Date }; + }): Promise<{ token: string }>; +} + +export class DefaultPluginTokenHandler implements PluginTokenHandler { private jwksMap = new Map(); // Tracking state for isTargetPluginSupported @@ -53,7 +67,7 @@ export class PluginTokenHandler { private targetPluginInflightChecks = new Map>(); static create(options: Options) { - return new PluginTokenHandler( + return new DefaultPluginTokenHandler( options.logger, options.ownPluginId, options.keySource, @@ -106,7 +120,8 @@ export class PluginTokenHandler { requiredClaims: ['iat', 'exp', 'sub', 'aud'], }, ).catch(e => { - throw new AuthenticationError('Invalid plugin token', e); + this.logger.warn('Failed to verify incoming plugin token', e); + throw new AuthenticationError('Failed plugin token verification'); }); return { subject: `plugin:${payload.sub}`, limitedUserToken: payload.obo }; @@ -115,7 +130,7 @@ export class PluginTokenHandler { async issueToken(options: { pluginId: string; targetPluginId: string; - onBehalfOf?: { token: string; expiresAt: Date }; + onBehalfOf?: { limitedUserToken: string; expiresAt: Date }; }): Promise<{ token: string }> { const { pluginId, targetPluginId, onBehalfOf } = options; const key = await this.keySource.getPrivateSigningKey(); @@ -131,7 +146,7 @@ export class PluginTokenHandler { ) : ourExp; - const claims = { sub, aud, iat, exp, obo: onBehalfOf?.token }; + const claims = { sub, aud, iat, exp, obo: onBehalfOf?.limitedUserToken }; const token = await new SignJWT(claims) .setProtectedHeader({ typ: tokenTypes.plugin.typParam, @@ -181,6 +196,7 @@ export class PluginTokenHandler { this.supportedTargetPlugins.add(targetPluginId); return true; } catch (error) { + assertError(error); this.logger.error('Unexpected failure for target JWKS check', error); return false; } finally { diff --git a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts index e85ec8db63..251e4c3adf 100644 --- a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts +++ b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.test.ts @@ -64,13 +64,17 @@ async function createToken(options: { describe('UserTokenHandler', () => { let userTokenHandler: UserTokenHandler; + const logger = mockServices.logger.mock(); + registerMswTestHooks(server); beforeEach(() => { jest.useRealTimers(); + jest.resetAllMocks(); userTokenHandler = UserTokenHandler.create({ discovery: mockServices.discovery(), + logger, }); server.use( @@ -120,7 +124,7 @@ describe('UserTokenHandler', () => { signature: 'sig', }), ), - ).rejects.toThrow('signature verification failed'); + ).rejects.toThrow('Failed user token verification'); await expect( userTokenHandler.verifyToken( @@ -130,7 +134,7 @@ describe('UserTokenHandler', () => { signature: 'sig', }), ), - ).rejects.toThrow('signature verification failed'); + ).rejects.toThrow('Failed user token verification'); }); it('should fail to verify tokens that have a bad alg', async () => { @@ -156,8 +160,13 @@ describe('UserTokenHandler', () => { }); const token = `${header}.${payload}.`; + expect(logger.warn).not.toHaveBeenCalled(); await expect(userTokenHandler.verifyToken(token)).rejects.toThrow( - /Unsupported "alg" value/, + 'Failed user token verification', + ); + expect(logger.warn).toHaveBeenCalledWith( + 'Failed to verify incoming user token', + expect.any(Error), ); }); diff --git a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.ts b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.ts index 4dd1874843..d205fa6b82 100644 --- a/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.ts +++ b/packages/backend-defaults/src/entrypoints/auth/user/UserTokenHandler.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DiscoveryService } from '@backstage/backend-plugin-api'; +import { DiscoveryService, LoggerService } from '@backstage/backend-plugin-api'; import { AuthenticationError } from '@backstage/errors'; import { tokenTypes } from '@backstage/plugin-auth-node'; import { @@ -33,15 +33,21 @@ import { JwksClient } from '../JwksClient'; * @internal */ export class UserTokenHandler { - static create(options: { discovery: DiscoveryService }): UserTokenHandler { + static create(options: { + discovery: DiscoveryService; + logger: LoggerService; + }): UserTokenHandler { const jwksClient = new JwksClient(async () => { const url = await options.discovery.getBaseUrl('auth'); return new URL(`${url}/.well-known/jwks.json`); }); - return new UserTokenHandler(jwksClient); + return new UserTokenHandler(jwksClient, options.logger); } - constructor(private readonly jwksClient: JwksClient) {} + constructor( + private readonly jwksClient: JwksClient, + private readonly logger: LoggerService, + ) {} async verifyToken(token: string) { const verifyOpts = this.#getTokenVerificationOptions(token); @@ -57,7 +63,8 @@ export class UserTokenHandler { this.jwksClient.getKey, verifyOpts, ).catch(e => { - throw new AuthenticationError('Invalid token', e); + this.logger.warn('Failed to verify incoming user token', e); + throw new AuthenticationError('Failed user token verification'); }); const userEntityRef = payload.sub; diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts index 997739faa2..d15671d5d2 100644 --- a/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.test.ts @@ -25,15 +25,21 @@ import { CacheManager } from './CacheManager'; // Contrived code because it's hard to spy on a default export jest.mock('@keyv/redis', () => { const Actual = jest.requireActual('@keyv/redis'); - return jest.fn((...args: any[]) => { - return new Actual(...args); - }); + const DefaultConstructor = Actual.default; + return { + ...Actual, + __esModule: true, + default: jest.fn((...args: any[]) => new DefaultConstructor(...args)), + }; }); jest.mock('@keyv/memcache', () => { const Actual = jest.requireActual('@keyv/memcache'); - return jest.fn((...args: any[]) => { - return new Actual(...args); - }); + const DefaultConstructor = Actual.default; + return { + ...Actual, + __esModule: true, + default: jest.fn((...args: any[]) => new DefaultConstructor(...args)), + }; }); describe('CacheManager integration', () => { @@ -42,7 +48,7 @@ describe('CacheManager integration', () => { afterEach(jest.clearAllMocks); it.each(caches.eachSupportedId())( - 'only creates one underlying connection, %p', + 'only creates one underlying connection per plugin, %p', async cacheId => { const { store, connection } = await caches.init(cacheId); @@ -59,10 +65,10 @@ describe('CacheManager integration', () => { if (store === 'redis') { // eslint-disable-next-line jest/no-conditional-expect - expect(KeyvRedis).toHaveBeenCalledTimes(1); + expect(KeyvRedis).toHaveBeenCalledTimes(3); } else if (store === 'memcache') { // eslint-disable-next-line jest/no-conditional-expect - expect(KeyvMemcache).toHaveBeenCalledTimes(1); + expect(KeyvMemcache).toHaveBeenCalledTimes(3); } }, ); @@ -185,6 +191,6 @@ describe('CacheManager integration', () => { }, }), ), - ).toThrow(/Invalid configuration backend.cache.defaultTtl/); + ).toThrow(/Invalid duration 'hello' in config/); }); }); diff --git a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts index a54959f155..57c326f00d 100644 --- a/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts +++ b/packages/backend-defaults/src/entrypoints/cache/CacheManager.ts @@ -24,6 +24,7 @@ import Keyv from 'keyv'; import { DefaultCacheClient } from './CacheClient'; import { CacheManagerOptions, ttlToMilliseconds } from './types'; import { durationToMilliseconds } from '@backstage/types'; +import { readDurationFromConfig } from '@backstage/config'; type StoreFactory = (pluginId: string, defaultTtl: number | undefined) => Keyv; @@ -48,7 +49,6 @@ export class CacheManager { private readonly logger?: LoggerService; private readonly store: keyof CacheManager['storeFactories']; private readonly connection: string; - private readonly useRedisSets: boolean; private readonly errorHandler: CacheManagerOptions['onError']; private readonly defaultTtl?: number; @@ -68,24 +68,23 @@ export class CacheManager { const defaultTtlConfig = config.getOptional('backend.cache.defaultTtl'); const connectionString = config.getOptionalString('backend.cache.connection') || ''; - const useRedisSets = - config.getOptionalBoolean('backend.cache.useRedisSets') ?? true; const logger = options.logger?.child({ type: 'cacheManager', }); + if (config.has('backend.cache.useRedisSets')) { + logger?.warn( + "The 'backend.cache.useRedisSets' configuration key is deprecated and no longer has any effect. The underlying '@keyv/redis' library no longer supports redis sets.", + ); + } + let defaultTtl: number | undefined; - if (defaultTtlConfig !== undefined && defaultTtlConfig !== null) { + if (defaultTtlConfig !== undefined) { if (typeof defaultTtlConfig === 'number') { defaultTtl = defaultTtlConfig; - } else if ( - typeof defaultTtlConfig === 'object' && - !Array.isArray(defaultTtlConfig) - ) { - defaultTtl = durationToMilliseconds(defaultTtlConfig); } else { - throw new Error( - `Invalid configuration backend.cache.defaultTtl: ${defaultTtlConfig}, expected milliseconds number or HumanDuration object`, + defaultTtl = durationToMilliseconds( + readDurationFromConfig(config, { key: 'backend.cache.defaultTtl' }), ); } } @@ -93,7 +92,6 @@ export class CacheManager { return new CacheManager( store, connectionString, - useRedisSets, options.onError, logger, defaultTtl, @@ -104,7 +102,6 @@ export class CacheManager { constructor( store: string, connectionString: string, - useRedisSets: boolean, errorHandler: CacheManagerOptions['onError'], logger?: LoggerService, defaultTtl?: number, @@ -115,7 +112,6 @@ export class CacheManager { this.logger = logger; this.store = store as keyof CacheManager['storeFactories']; this.connection = connectionString; - this.useRedisSets = useRedisSets; this.errorHandler = errorHandler; this.defaultTtl = defaultTtl; } @@ -143,15 +139,16 @@ export class CacheManager { } private createRedisStoreFactory(): StoreFactory { - const KeyvRedis = require('@keyv/redis'); - let store: typeof KeyvRedis | undefined; + const KeyvRedis = require('@keyv/redis').default; + const stores: Record = {}; + return (pluginId, defaultTtl) => { - if (!store) { - store = new KeyvRedis(this.connection, { - useRedisSets: this.useRedisSets, + if (!stores[pluginId]) { + stores[pluginId] = new KeyvRedis(this.connection, { + keyPrefixSeparator: ':', }); // Always provide an error handler to avoid stopping the process - store.on('error', (err: Error) => { + stores[pluginId].on('error', (err: Error) => { this.logger?.error('Failed to create redis cache client', err); this.errorHandler?.(err); }); @@ -159,21 +156,22 @@ export class CacheManager { return new Keyv({ namespace: pluginId, ttl: defaultTtl, - store, + store: stores[pluginId], emitErrors: false, - useRedisSets: this.useRedisSets, + useKeyPrefix: false, }); }; } private createMemcacheStoreFactory(): StoreFactory { - const KeyvMemcache = require('@keyv/memcache'); - let store: typeof KeyvMemcache | undefined; + const KeyvMemcache = require('@keyv/memcache').default; + const stores: Record = {}; + return (pluginId, defaultTtl) => { - if (!store) { - store = new KeyvMemcache(this.connection); + if (!stores[pluginId]) { + stores[pluginId] = new KeyvMemcache(this.connection); // Always provide an error handler to avoid stopping the process - store.on('error', (err: Error) => { + stores[pluginId].on('error', (err: Error) => { this.logger?.error('Failed to create memcache cache client', err); this.errorHandler?.(err); }); @@ -182,7 +180,7 @@ export class CacheManager { namespace: pluginId, ttl: defaultTtl, emitErrors: false, - store, + store: stores[pluginId], }); }; } diff --git a/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts index 1e07984967..1a3691c83b 100644 --- a/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.test.ts @@ -22,6 +22,8 @@ import { parsePgConnectionString, } from './postgres'; +jest.mock('@google-cloud/cloud-sql-connector'); + describe('postgres', () => { const createMockConnection = () => ({ host: 'acme', @@ -37,33 +39,35 @@ describe('postgres', () => { new ConfigReader({ client: 'pg', connection }); describe('buildPgDatabaseConfig', () => { - it('builds a postgres config', () => { + it('builds a postgres config', async () => { const mockConnection = createMockConnection(); - expect(buildPgDatabaseConfig(createConfig(mockConnection))).toEqual({ - client: 'pg', - connection: mockConnection, - useNullAsDefault: true, - }); - }); - - it('builds a connection string config', () => { - const mockConnectionString = createMockConnectionString(); - - expect(buildPgDatabaseConfig(createConfig(mockConnectionString))).toEqual( + expect(await buildPgDatabaseConfig(createConfig(mockConnection))).toEqual( { client: 'pg', - connection: mockConnectionString, + connection: mockConnection, useNullAsDefault: true, }, ); }); - it('overrides the database name', () => { + it('builds a connection string config', async () => { + const mockConnectionString = createMockConnectionString(); + + expect( + await buildPgDatabaseConfig(createConfig(mockConnectionString)), + ).toEqual({ + client: 'pg', + connection: mockConnectionString, + useNullAsDefault: true, + }); + }); + + it('overrides the database name', async () => { const mockConnection = createMockConnection(); expect( - buildPgDatabaseConfig(createConfig(mockConnection), { + await buildPgDatabaseConfig(createConfig(mockConnection), { connection: { database: 'other_db' }, }), ).toEqual({ @@ -76,14 +80,14 @@ describe('postgres', () => { }); }); - it('overrides the schema name', () => { + it('overrides the schema name', async () => { const mockConnection = { ...createMockConnection(), schema: 'schemaName', }; expect( - buildPgDatabaseConfig(createConfig(mockConnection), { + await buildPgDatabaseConfig(createConfig(mockConnection), { searchPath: ['schemaName'], }), ).toEqual({ @@ -94,11 +98,11 @@ describe('postgres', () => { }); }); - it('adds additional config settings', () => { + it('adds additional config settings', async () => { const mockConnection = createMockConnection(); expect( - buildPgDatabaseConfig(createConfig(mockConnection), { + await buildPgDatabaseConfig(createConfig(mockConnection), { connection: { database: 'other_db' }, pool: { min: 0, max: 7 }, debug: true, @@ -115,12 +119,12 @@ describe('postgres', () => { }); }); - it('overrides the database from connection string', () => { + it('overrides the database from connection string', async () => { const mockConnectionString = createMockConnectionString(); const mockConnection = createMockConnection(); expect( - buildPgDatabaseConfig(createConfig(mockConnectionString), { + await buildPgDatabaseConfig(createConfig(mockConnectionString), { connection: { database: 'other_db' }, }), ).toEqual({ @@ -133,6 +137,124 @@ describe('postgres', () => { useNullAsDefault: true, }); }); + + it('uses the correct config when using cloudsql', async () => { + expect( + await buildPgDatabaseConfig( + new ConfigReader({ + client: 'pg', + connection: { + type: 'cloudsql', + user: 'ben@gke.com', + instance: 'project:region:instance', + port: 5423, + }, + }), + { connection: { database: 'other_db' } }, + ), + ).toEqual({ + client: 'pg', + connection: { + user: 'ben@gke.com', + port: 5423, + database: 'other_db', + }, + useNullAsDefault: true, + }); + }); + + it('should throw with incorrect config', async () => { + await expect( + buildPgDatabaseConfig( + new ConfigReader({ + client: 'pg', + connection: { + type: 'cloudsql', + }, + }), + ), + ).rejects.toThrow(/Missing instance connection name for Cloud SQL/); + + await expect( + buildPgDatabaseConfig( + new ConfigReader({ + client: 'not-pg', + connection: { + type: 'cloudsql', + instance: 'asd:asd:asd', + }, + }), + ), + ).rejects.toThrow(/Cloud SQL only supports the pg client/); + }); + + it('adds the settings from cloud-sql-connector', async () => { + const { Connector } = jest.requireMock( + '@google-cloud/cloud-sql-connector', + ) as jest.Mocked; + + const mockStream = (): any => {}; + Connector.prototype.getOptions.mockResolvedValue({ stream: mockStream }); + + expect( + await buildPgDatabaseConfig( + new ConfigReader({ + client: 'pg', + connection: { + type: 'cloudsql', + user: 'ben@gke.com', + instance: 'project:region:instance', + port: 5423, + }, + }), + { connection: { database: 'other_db' } }, + ), + ).toEqual({ + client: 'pg', + connection: { + user: 'ben@gke.com', + port: 5423, + stream: mockStream, + database: 'other_db', + }, + useNullAsDefault: true, + }); + }); + + it('throws an error when the connection type is not supported', async () => { + await expect( + buildPgDatabaseConfig( + new ConfigReader({ + client: 'pg', + connection: { + type: 'not-supported', + }, + }), + ), + ).rejects.toThrow('Unknown connection type: not-supported'); + }); + + it('supports default as the default connection type', async () => { + await expect( + buildPgDatabaseConfig( + new ConfigReader({ + client: 'pg', + connection: { + type: 'default', + port: '5432', + database: 'other_db', + }, + }), + ), + ).resolves.toEqual({ + client: 'pg', + connection: { + port: '5432', + database: 'other_db', + }, + useNullAsDefault: true, + }); + }); }); describe('getPgConnectionConfig', () => { @@ -174,9 +296,9 @@ describe('postgres', () => { }); describe('createPgDatabaseClient', () => { - it('creates a postgres knex instance', () => { + it('creates a postgres knex instance', async () => { expect( - createPgDatabaseClient( + await createPgDatabaseClient( createConfig({ host: 'acme', user: 'foo', @@ -187,14 +309,14 @@ describe('postgres', () => { ).toBeTruthy(); }); - it('attempts to read an ssl cert', () => { - expect(() => + it('attempts to read an ssl cert', async () => { + await expect(() => createPgDatabaseClient( createConfig( 'postgresql://postgres:pass@localhost:5432/dbname?sslrootcert=/path/to/file', ), ), - ).toThrow(/no such file or directory/); + ).rejects.toThrow(/no such file or directory/); }); }); diff --git a/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts index b5cfffd1f4..e7e973ae4b 100644 --- a/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts +++ b/packages/backend-defaults/src/entrypoints/database/connectors/postgres.ts @@ -37,11 +37,11 @@ const ddlLimiter = limiterFactory(1); * @param dbConfig - The database config * @param overrides - Additional options to merge with the config */ -export function createPgDatabaseClient( +export async function createPgDatabaseClient( dbConfig: Config, overrides?: Knex.Config, ) { - const knexConfig = buildPgDatabaseConfig(dbConfig, overrides); + const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides); const database = knexFactory(knexConfig); const role = dbConfig.getOptionalString('role'); @@ -64,11 +64,11 @@ export function createPgDatabaseClient( * @param dbConfig - The database config * @param overrides - Additional options to merge with the config */ -export function buildPgDatabaseConfig( +export async function buildPgDatabaseConfig( dbConfig: Config, overrides?: Knex.Config, ) { - return mergeDatabaseConfig( + const config = mergeDatabaseConfig( dbConfig.get(), { connection: getPgConnectionConfig(dbConfig, !!overrides), @@ -76,6 +76,49 @@ export function buildPgDatabaseConfig( }, overrides, ); + + const sanitizedConfig = JSON.parse(JSON.stringify(config)); + + // Trim additional properties from the connection object passed to knex + delete sanitizedConfig.connection.type; + delete sanitizedConfig.connection.instance; + + if (config.connection.type === 'default' || !config.connection.type) { + return sanitizedConfig; + } + + if (config.connection.type !== 'cloudsql') { + throw new Error(`Unknown connection type: ${config.connection.type}`); + } + + if (config.client !== 'pg') { + throw new Error('Cloud SQL only supports the pg client'); + } + + if (!config.connection.instance) { + throw new Error('Missing instance connection name for Cloud SQL'); + } + + const { + Connector: CloudSqlConnector, + IpAddressTypes, + AuthTypes, + } = await import('@google-cloud/cloud-sql-connector'); + const connector = new CloudSqlConnector(); + const clientOpts = await connector.getOptions({ + instanceConnectionName: config.connection.instance, + ipType: IpAddressTypes.PUBLIC, + authType: AuthTypes.IAM, + }); + + return { + ...sanitizedConfig, + client: 'pg', + connection: { + ...sanitizedConfig.connection, + ...clientOpts, + }, + }; } /** @@ -130,7 +173,7 @@ export async function ensurePgDatabaseExists( dbConfig: Config, ...databases: Array ) { - const admin = createPgDatabaseClient(dbConfig, { + const admin = await createPgDatabaseClient(dbConfig, { connection: { database: 'postgres', }, @@ -186,7 +229,7 @@ export async function ensurePgSchemaExists( dbConfig: Config, ...schemas: Array ): Promise { - const admin = createPgDatabaseClient(dbConfig); + const admin = await createPgDatabaseClient(dbConfig); const role = dbConfig.getOptionalString('role'); try { @@ -219,7 +262,7 @@ export async function dropPgDatabase( dbConfig: Config, ...databases: Array ) { - const admin = createPgDatabaseClient(dbConfig); + const admin = await createPgDatabaseClient(dbConfig); try { await Promise.all( databases.map(async database => { diff --git a/packages/backend-defaults/src/entrypoints/httpAuth/DefaultHttpAuthService.test.ts b/packages/backend-defaults/src/entrypoints/httpAuth/DefaultHttpAuthService.test.ts new file mode 100644 index 0000000000..e314564b59 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/httpAuth/DefaultHttpAuthService.test.ts @@ -0,0 +1,42 @@ +/* + * 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 { DefaultHttpAuthService } from './httpAuthServiceFactory'; +import { mockServices } from '@backstage/backend-test-utils'; +import { createRequest } from 'node-mocks-http'; + +describe('DefaultHttpAuthService', () => { + it('should extract token from custom header', async () => { + const auth = mockServices.auth.mock(); + const httpAuthService = DefaultHttpAuthService.create({ + discovery: mockServices.discovery(), + auth, + pluginId: 'test', + getTokenFromRequest: req => { + let token: string | undefined; + const header = req.headers.test; + if (typeof header === 'string') { + token = header; + } + return { token }; + }, + }); + await httpAuthService.credentials( + createRequest({ headers: { test: 'mock-user-token' } }), + ); + expect(auth.authenticate).toHaveBeenCalledWith('mock-user-token'); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/httpAuth/httpAuthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/httpAuth/httpAuthServiceFactory.ts index 76550873f6..4bc6b3b1fc 100644 --- a/packages/backend-defaults/src/entrypoints/httpAuth/httpAuthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/httpAuth/httpAuthServiceFactory.ts @@ -33,17 +33,14 @@ const FIVE_MINUTES_MS = 5 * 60 * 1000; const BACKSTAGE_AUTH_COOKIE = 'backstage-auth'; function getTokenFromRequest(req: Request) { - // TODO: support multiple auth headers (iterate rawHeaders) + let token: string | undefined; const authHeader = req.headers.authorization; if (typeof authHeader === 'string') { const matches = authHeader.match(/^Bearer[ ]+(\S+)$/i); - const token = matches?.[1]; - if (token) { - return token; - } + token = matches?.[1]; } - return undefined; + return { token }; } function getCookieFromRequest(req: Request) { @@ -71,23 +68,55 @@ type RequestWithCredentials = Request & { [limitedCredentialsSymbol]?: Promise; }; -class DefaultHttpAuthService implements HttpAuthService { +/** + * @public + * Options for creating a DefaultHttpAuthService. + */ +export interface DefaultHttpAuthServiceOptions { + auth: AuthService; + discovery: DiscoveryService; + pluginId: string; + /** + * Optionally override logic for extracting the token from the request. + */ + getTokenFromRequest?: (req: Request) => { token?: string }; +} + +/** + * @public + * DefaultHttpAuthService is the default implementation of the HttpAuthService + */ +export class DefaultHttpAuthService implements HttpAuthService { readonly #auth: AuthService; readonly #discovery: DiscoveryService; readonly #pluginId: string; + readonly #getToken: (req: Request) => { token?: string }; - constructor( + private constructor( auth: AuthService, discovery: DiscoveryService, pluginId: string, + getToken?: (req: Request) => { token?: string }, ) { this.#auth = auth; this.#discovery = discovery; this.#pluginId = pluginId; + this.#getToken = getToken ?? getTokenFromRequest; + } + + static create( + options: DefaultHttpAuthServiceOptions, + ): DefaultHttpAuthService { + return new DefaultHttpAuthService( + options.auth, + options.discovery, + options.pluginId, + options.getTokenFromRequest, + ); } async #extractCredentialsFromRequest(req: Request) { - const token = getTokenFromRequest(req); + const { token } = this.#getToken(req); if (!token) { return await this.#auth.getNoneCredentials(); } @@ -96,7 +125,7 @@ class DefaultHttpAuthService implements HttpAuthService { } async #extractLimitedCredentialsFromRequest(req: Request) { - const token = getTokenFromRequest(req); + const { token } = this.#getToken(req); if (token) { return await this.#auth.authenticate(token, { allowLimitedAccess: true, @@ -289,6 +318,10 @@ export const httpAuthServiceFactory = createServiceFactory({ plugin: coreServices.pluginMetadata, }, async factory({ auth, discovery, plugin }) { - return new DefaultHttpAuthService(auth, discovery, plugin.getId()); + return DefaultHttpAuthService.create({ + auth, + discovery, + pluginId: plugin.getId(), + }); }, }); diff --git a/packages/backend-defaults/src/entrypoints/httpAuth/index.ts b/packages/backend-defaults/src/entrypoints/httpAuth/index.ts index edd7e53026..9afe06ae0e 100644 --- a/packages/backend-defaults/src/entrypoints/httpAuth/index.ts +++ b/packages/backend-defaults/src/entrypoints/httpAuth/index.ts @@ -14,4 +14,8 @@ * limitations under the License. */ -export { httpAuthServiceFactory } from './httpAuthServiceFactory'; +export { + httpAuthServiceFactory, + DefaultHttpAuthService, +} from './httpAuthServiceFactory'; +export type { DefaultHttpAuthServiceOptions } from './httpAuthServiceFactory'; diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createLifecycleMiddleware.ts b/packages/backend-defaults/src/entrypoints/httpRouter/createLifecycleMiddleware.ts index 18ff2f0840..99fb82a41e 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/createLifecycleMiddleware.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/createLifecycleMiddleware.ts @@ -14,19 +14,20 @@ * limitations under the License. */ -import { LifecycleService } from '@backstage/backend-plugin-api'; +import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { ServiceUnavailableError } from '@backstage/errors'; import { HumanDuration, durationToMilliseconds } from '@backstage/types'; import { RequestHandler } from 'express'; -export const DEFAULT_TIMEOUT = { seconds: 5 }; +export const DEFAULT_STARTUP_REQUEST_PAUSE_TIMEOUT = { seconds: 5 }; +export const DEFAULT_SERVER_SHUTDOWN_TIMEOUT = { seconds: 0 }; /** * Options for {@link createLifecycleMiddleware}. - * @internal + * @public */ export interface LifecycleMiddlewareOptions { - lifecycle: LifecycleService; + lifecycle: RootLifecycleService; /** * The maximum time that paused requests will wait for the service to start, before returning an error. * @@ -47,12 +48,12 @@ export interface LifecycleMiddlewareOptions { * If the service is shutting down, all requests will be rejected with a * {@link @backstage/errors#ServiceUnavailableError}. * - * @internal + * @public */ export function createLifecycleMiddleware( options: LifecycleMiddlewareOptions, ): RequestHandler { - const { lifecycle, startupRequestPauseTimeout = DEFAULT_TIMEOUT } = options; + const { lifecycle, startupRequestPauseTimeout } = options; let state: 'init' | 'up' | 'down' = 'init'; const waiting = new Set<{ @@ -73,7 +74,6 @@ export function createLifecycleMiddleware( lifecycle.addShutdownHook(async () => { state = 'down'; - for (const item of waiting) { clearTimeout(item.timeout); item.next(new ServiceUnavailableError('Service is shutting down')); @@ -81,8 +81,6 @@ export function createLifecycleMiddleware( waiting.clear(); }); - const timeoutMs = durationToMilliseconds(startupRequestPauseTimeout); - return (_req, _res, next) => { if (state === 'up') { next(); @@ -92,6 +90,10 @@ export function createLifecycleMiddleware( return; } + const timeoutMs = durationToMilliseconds( + startupRequestPauseTimeout ?? DEFAULT_STARTUP_REQUEST_PAUSE_TIMEOUT, + ); + const item = { next, timeout: setTimeout(() => { diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createAuthIntegrationRouter.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createAuthIntegrationRouter.ts similarity index 98% rename from packages/backend-defaults/src/entrypoints/httpRouter/createAuthIntegrationRouter.ts rename to packages/backend-defaults/src/entrypoints/httpRouter/http/createAuthIntegrationRouter.ts index ef36e7ba2d..3d36ef8e34 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/createAuthIntegrationRouter.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/createAuthIntegrationRouter.ts @@ -18,6 +18,9 @@ import { AuthService } from '@backstage/backend-plugin-api'; import express from 'express'; import Router from 'express-promise-router'; +/** + * @public + */ export function createAuthIntegrationRouter(options: { auth: AuthService; }): express.Router { diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.test.ts similarity index 100% rename from packages/backend-defaults/src/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.test.ts rename to packages/backend-defaults/src/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.test.ts diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.ts similarity index 100% rename from packages/backend-defaults/src/entrypoints/httpRouter/createCookieAuthRefreshMiddleware.ts rename to packages/backend-defaults/src/entrypoints/httpRouter/http/createCookieAuthRefreshMiddleware.ts diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createCredentialsBarrier.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createCredentialsBarrier.test.ts similarity index 100% rename from packages/backend-defaults/src/entrypoints/httpRouter/createCredentialsBarrier.test.ts rename to packages/backend-defaults/src/entrypoints/httpRouter/http/createCredentialsBarrier.test.ts diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/createCredentialsBarrier.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createCredentialsBarrier.ts similarity index 99% rename from packages/backend-defaults/src/entrypoints/httpRouter/createCredentialsBarrier.ts rename to packages/backend-defaults/src/entrypoints/httpRouter/http/createCredentialsBarrier.ts index dd6c95ca82..f6332c6d28 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/createCredentialsBarrier.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/createCredentialsBarrier.ts @@ -36,6 +36,9 @@ export function createPathPolicyPredicate(policyPath: string) { }; } +/** + * @public + */ export function createCredentialsBarrier(options: { httpAuth: HttpAuthService; config: RootConfigService; diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.test.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.test.ts new file mode 100644 index 0000000000..36ca2da61b --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.test.ts @@ -0,0 +1,93 @@ +/* + * Copyright 2022 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 { createLifecycleMiddleware } from './createLifecycleMiddleware'; +import { BackendLifecycleImpl } from '../../rootLifecycle/rootLifecycleServiceFactory'; +import { mockServices } from '@backstage/backend-test-utils'; +import { ServiceUnavailableError } from '@backstage/errors'; + +describe('createLifecycleMiddleware', () => { + const config = mockServices.rootConfig.mock(); + it('should pause requests when plugin is not ready', async () => { + const lifecycle = new BackendLifecycleImpl(mockServices.rootLogger()); + + const middleware = createLifecycleMiddleware({ + config, + lifecycle, + }); + + const next = jest.fn(); + middleware({} as any, {} as any, next); + expect(next).not.toHaveBeenCalled(); + await lifecycle.startup(); + + // pending call + expect(next).toHaveBeenCalledWith(); + + // new call + const next2 = jest.fn(); + middleware({} as any, {} as any, next2); + expect(next2).toHaveBeenCalledWith(); + }); + + it('should throw ServiceUnavailableError after shutdown', async () => { + const lifecycle = new BackendLifecycleImpl(mockServices.rootLogger()); + const middleware = createLifecycleMiddleware({ config, lifecycle }); + + const next = jest.fn(); + middleware({} as any, {} as any, next); + expect(next).not.toHaveBeenCalled(); + await lifecycle.shutdown(); + + // pending call + expect(next).toHaveBeenCalledWith( + new ServiceUnavailableError('Service is shutting down'), + ); + + // new call + const next2 = jest.fn(); + middleware({} as any, {} as any, next2); + expect(next2).toHaveBeenCalledWith( + new ServiceUnavailableError('Service is shutting down'), + ); + }); + + it('should throw ServiceUnavailableError after timeout', async () => { + const lifecycle = new BackendLifecycleImpl(mockServices.rootLogger()); + const middleware = createLifecycleMiddleware({ + lifecycle, + config: mockServices.rootConfig({ + data: { + backend: { + lifecycle: { + startupRequestPauseTimeout: { milliseconds: 1 }, + }, + }, + }, + }), + }); + + const next = jest.fn(); + middleware({} as any, {} as any, next); + expect(next).not.toHaveBeenCalled(); + + await new Promise(r => setTimeout(r, 2)); + + expect(next).toHaveBeenCalledWith( + new ServiceUnavailableError('Service has not started up yet'), + ); + }); +}); diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.ts new file mode 100644 index 0000000000..366d19f8bf --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/createLifecycleMiddleware.ts @@ -0,0 +1,113 @@ +/* + * Copyright 2022 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, + LifecycleService, +} from '@backstage/backend-plugin-api'; +import { readDurationFromConfig } from '@backstage/config'; +import { ServiceUnavailableError } from '@backstage/errors'; +import { HumanDuration, durationToMilliseconds } from '@backstage/types'; +import { RequestHandler } from 'express'; + +export const DEFAULT_TIMEOUT = { seconds: 5 }; + +/** + * Options for {@link createLifecycleMiddleware}. + * @public + */ +export interface LifecycleMiddlewareOptions { + config: RootConfigService; + lifecycle: LifecycleService; +} + +/** + * Creates a middleware that pauses requests until the service has started. + * + * @remarks + * + * Requests that arrive before the service has started will be paused until startup is complete. + * If the service does not start within the provided timeout, the request will be rejected with a + * {@link @backstage/errors#ServiceUnavailableError}. + * + * If the service is shutting down, all requests will be rejected with a + * {@link @backstage/errors#ServiceUnavailableError}. + * + * @public + */ +export function createLifecycleMiddleware( + options: LifecycleMiddlewareOptions, +): RequestHandler { + const { config, lifecycle } = options; + + let state: 'init' | 'up' | 'down' = 'init'; + const waiting = new Set<{ + next: (err?: Error) => void; + timeout: NodeJS.Timeout; + }>(); + + lifecycle.addStartupHook(async () => { + if (state === 'init') { + state = 'up'; + for (const item of waiting) { + clearTimeout(item.timeout); + item.next(); + } + waiting.clear(); + } + }); + + lifecycle.addShutdownHook(async () => { + state = 'down'; + + for (const item of waiting) { + clearTimeout(item.timeout); + item.next(new ServiceUnavailableError('Service is shutting down')); + } + waiting.clear(); + }); + + let startupRequestPauseTimeout: HumanDuration = DEFAULT_TIMEOUT; + + if (config.has('backend.lifecycle.startupRequestPauseTimeout')) { + startupRequestPauseTimeout = readDurationFromConfig(config, { + key: 'backend.lifecycle.startupRequestPauseTimeout', + }); + } + + const timeoutMs = durationToMilliseconds(startupRequestPauseTimeout); + + return (_req, _res, next) => { + if (state === 'up') { + next(); + return; + } else if (state === 'down') { + next(new ServiceUnavailableError('Service is shutting down')); + return; + } + + const item = { + next, + timeout: setTimeout(() => { + if (waiting.delete(item)) { + next(new ServiceUnavailableError('Service has not started up yet')); + } + }, timeoutMs), + }; + + waiting.add(item); + }; +} diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/http/index.ts b/packages/backend-defaults/src/entrypoints/httpRouter/http/index.ts new file mode 100644 index 0000000000..d31ea74fe8 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/httpRouter/http/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ +export { createAuthIntegrationRouter } from './createAuthIntegrationRouter'; +export { createCredentialsBarrier } from './createCredentialsBarrier'; +export { createLifecycleMiddleware } from './createLifecycleMiddleware'; +export type { LifecycleMiddlewareOptions } from './createLifecycleMiddleware'; +export { createCookieAuthRefreshMiddleware } from './createCookieAuthRefreshMiddleware'; diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts index fb2646580b..6f8792aa3d 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/httpRouterServiceFactory.ts @@ -21,10 +21,12 @@ import { createServiceFactory, HttpRouterServiceAuthPolicy, } from '@backstage/backend-plugin-api'; -import { createLifecycleMiddleware } from './createLifecycleMiddleware'; -import { createCredentialsBarrier } from './createCredentialsBarrier'; -import { createAuthIntegrationRouter } from './createAuthIntegrationRouter'; -import { createCookieAuthRefreshMiddleware } from './createCookieAuthRefreshMiddleware'; +import { + createLifecycleMiddleware, + createCookieAuthRefreshMiddleware, + createCredentialsBarrier, + createAuthIntegrationRouter, +} from './http'; /** * HTTP route registration for plugins. @@ -57,7 +59,7 @@ export const httpRouterServiceFactory = createServiceFactory({ }); router.use(createAuthIntegrationRouter({ auth })); - router.use(createLifecycleMiddleware({ lifecycle })); + router.use(createLifecycleMiddleware({ config, lifecycle })); router.use(credentialsBarrier.middleware); router.use(createCookieAuthRefreshMiddleware({ auth, httpAuth })); diff --git a/packages/backend-defaults/src/entrypoints/httpRouter/index.ts b/packages/backend-defaults/src/entrypoints/httpRouter/index.ts index 15bced5ef3..fc9752bdc1 100644 --- a/packages/backend-defaults/src/entrypoints/httpRouter/index.ts +++ b/packages/backend-defaults/src/entrypoints/httpRouter/index.ts @@ -15,3 +15,4 @@ */ export { httpRouterServiceFactory } from './httpRouterServiceFactory'; +export * from './http'; diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts index 0eee5c18c6..ca9085273c 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.test.ts @@ -53,11 +53,11 @@ describe('DefaultRootHealthService', () => { it(`should return a 500 response if the server has stopped`, async () => { let mockServerStartedFn = () => {}; - let mockServerStoppedFn = () => {}; + let mockServerBeforeStoppedFn = () => {}; const lifecycle = mockServices.rootLifecycle.mock({ addStartupHook: jest.fn(fn => (mockServerStartedFn = fn)), - addShutdownHook: jest.fn(fn => (mockServerStoppedFn = fn)), + addBeforeShutdownHook: jest.fn(fn => (mockServerBeforeStoppedFn = fn)), }); const service = new DefaultRootHealthService({ @@ -65,11 +65,11 @@ describe('DefaultRootHealthService', () => { }); mockServerStartedFn(); - mockServerStoppedFn(); + mockServerBeforeStoppedFn(); await expect(service.getReadiness()).resolves.toEqual({ status: 503, payload: { - message: 'Backend has not started yet', + message: 'Backend is shuttting down', status: 'error', }, }); diff --git a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts index c8b4ad5394..b201079b4f 100644 --- a/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHealth/rootHealthServiceFactory.ts @@ -23,14 +23,14 @@ import { /** @internal */ export class DefaultRootHealthService implements RootHealthService { - #isRunning = false; + #state: 'init' | 'up' | 'down' = 'init'; constructor(readonly options: { lifecycle: RootLifecycleService }) { options.lifecycle.addStartupHook(() => { - this.#isRunning = true; + this.#state = 'up'; }); - options.lifecycle.addShutdownHook(() => { - this.#isRunning = false; + options.lifecycle.addBeforeShutdownHook(() => { + this.#state = 'down'; }); } @@ -39,12 +39,18 @@ export class DefaultRootHealthService implements RootHealthService { } async getReadiness(): Promise<{ status: number; payload?: any }> { - if (!this.#isRunning) { + if (this.#state === 'init') { return { status: 503, payload: { message: 'Backend has not started yet', status: 'error' }, }; } + if (this.#state === 'down') { + return { + status: 503, + payload: { message: 'Backend is shuttting down', status: 'error' }, + }; + } return { status: 200, payload: { status: 'ok' } }; } diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts index 3772ab0fab..a22f4f32a0 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/createHealthRouter.ts @@ -14,20 +14,50 @@ * limitations under the License. */ -import { RootHealthService } from '@backstage/backend-plugin-api'; +import { + RootConfigService, + RootHealthService, +} from '@backstage/backend-plugin-api'; import Router from 'express-promise-router'; import { Request, Response } from 'express'; +const HEADER_CONFIG_KEY = 'backend.health.headers'; + /** * @public */ -export function createHealthRouter(options: { health: RootHealthService }) { +export function createHealthRouter(options: { + health: RootHealthService; + config: RootConfigService; +}) { + const headersConfig = options.config + .getOptionalConfig(HEADER_CONFIG_KEY) + ?.get(); + if (headersConfig) { + for (const [key, value] of Object.entries(headersConfig)) { + if (!key || typeof key !== 'string') { + throw new Error( + `Invalid header name in at ${HEADER_CONFIG_KEY}, must be a non-empty string`, + ); + } + if (!value || typeof value !== 'string') { + throw new Error( + `Invalid header value in at ${HEADER_CONFIG_KEY}, must be a non-empty string`, + ); + } + } + } + const headers = headersConfig && new Headers(headersConfig as HeadersInit); + const router = Router(); router.get( '/.backstage/health/v1/readiness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getReadiness(); + if (headers) { + response.setHeaders(headers); + } response.status(status).json(payload); }, ); @@ -36,6 +66,9 @@ export function createHealthRouter(options: { health: RootHealthService }) { '/.backstage/health/v1/liveness', async (_request: Request, response: Response) => { const { status, payload } = await options.health.getLiveness(); + if (headers) { + response.setHeaders(headers); + } response.status(status).json(payload); }, ); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.test.ts index 418d170365..1c140791b6 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.test.ts @@ -27,33 +27,22 @@ import express from 'express'; import createError from 'http-errors'; import request from 'supertest'; import { MiddlewareFactory } from './MiddlewareFactory'; -import { ConfigReader } from '@backstage/config'; +import { mockServices } from '@backstage/backend-test-utils'; + +jest.useFakeTimers({ now: new Date('2024-11-20T00:00:00Z') }); describe('MiddlewareFactory', () => { describe('middleware.error', () => { - const childLogger = { - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - debug: jest.fn(), - child: jest.fn(), - }; - - const logger = { - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - debug: jest.fn(), - child: () => childLogger, - }; + const childLogger = mockServices.logger.mock(); + const logger = mockServices.logger.mock({ child: () => childLogger }); const middleware = MiddlewareFactory.create({ logger, - config: new ConfigReader({}), + config: mockServices.rootConfig.mock(), }); beforeEach(() => { - jest.resetAllMocks(); + jest.clearAllMocks(); }); it('gives default code and message', async () => { @@ -195,9 +184,7 @@ describe('MiddlewareFactory', () => { it('should filter out internal errors', async () => { const app = express(); - const grandChildLogger = { - error: jest.fn(), - }; + const grandChildLogger = mockServices.logger.mock(); childLogger.child.mockReturnValue(grandChildLogger); class DatabaseError extends Error {} @@ -254,5 +241,57 @@ describe('MiddlewareFactory', () => { expect(childLogger.error).toHaveBeenCalled(); }); + + it('should log incoming requests', async () => { + const app = express(); + app.use(middleware.logging()); + app.get('/', (_req, res) => res.send('')); + + await request(app).get('/').expect(200); + + expect(logger.info).toHaveBeenCalledWith( + expect.stringContaining( + '[2024-11-20T00:00:00.000Z] "GET / HTTP/1.1" 200 0 "-" "-"', + ), + { + type: 'incomingRequest', + date: '2024-11-20T00:00:00.000Z', + method: 'GET', + url: '/', + status: 200, + httpVersion: '1.1', + contentLength: 0, + }, + ); + }); + + it('should log request with all data fields', async () => { + const app = express(); + app.use(middleware.logging()); + app.get('/', (_req, res) => res.send('Hello World')); + + await request(app) + .get('/') + .set('User-Agent', 'test-agent') + .set('referrer', 'test-referrer') + .expect(200); + + expect(logger.info).toHaveBeenCalledWith( + expect.stringContaining( + '[2024-11-20T00:00:00.000Z] "GET / HTTP/1.1" 200 11 "test-referrer" "test-agent"', + ), + { + type: 'incomingRequest', + date: '2024-11-20T00:00:00.000Z', + method: 'GET', + url: '/', + status: 200, + httpVersion: '1.1', + userAgent: 'test-agent', + referrer: 'test-referrer', + contentLength: 11, + }, + ); + }); }); }); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts index f38c10820a..1ff9bd15d1 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/MiddlewareFactory.ts @@ -27,7 +27,6 @@ import { } from 'express'; import cors from 'cors'; import helmet from 'helmet'; -import morgan from 'morgan'; import compression from 'compression'; import { readHelmetOptions } from './readHelmetOptions'; import { readCorsOptions } from './readCorsOptions'; @@ -45,6 +44,45 @@ import { import { NotImplementedError } from '@backstage/errors'; import { applyInternalErrorFilter } from './applyInternalErrorFilter'; +type LogMeta = { + date: string; + method: string; + url: string; + status: number; + httpVersion: string; + userAgent?: string; + contentLength?: number; + referrer?: string; +}; + +function getLogMeta(req: Request, res: Response): LogMeta { + const referrer = req.headers.referer ?? req.headers.referrer; + const userAgent = req.headers['user-agent']; + const contentLength = Number(res.getHeader('content-length')); + + const meta: LogMeta = { + date: new Date().toISOString(), + method: req.method, + url: req.originalUrl ?? req.url, + status: res.statusCode, + httpVersion: `${req.httpVersionMajor}.${req.httpVersionMinor}`, + }; + + if (userAgent) { + meta.userAgent = userAgent; + } + + if (isFinite(contentLength)) { + meta.contentLength = contentLength; + } + + if (referrer) { + meta.referrer = Array.isArray(referrer) ? referrer.join(', ') : referrer; + } + + return meta; +} + /** * Options used to create a {@link MiddlewareFactory}. * @@ -137,18 +175,24 @@ export class MiddlewareFactory { * @returns An Express request handler */ logging(): RequestHandler { - const logger = this.#logger.child({ - type: 'incomingRequest', - }); - const customMorganFormat = - '[:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'; - return morgan(customMorganFormat, { - stream: { - write(message: string) { - logger.info(message.trimEnd()); - }, - }, - }); + const logger = this.#logger; + return (req: Request, res: Response, next: NextFunction) => { + res.on('finish', () => { + const meta = getLogMeta(req, res); + logger.info( + `[${meta.date}] "${meta.method} ${meta.url} HTTP/${ + meta.httpVersion + }" ${meta.status} ${meta.contentLength ?? 0} "${ + meta.referrer ?? '-' + }" "${meta.userAgent ?? '-'}"`, + { + type: 'incomingRequest', + ...meta, + }, + ); + }); + next(); + }; } /** diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/createHttpServer.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/createHttpServer.ts index 5c526ba1e2..fbb6ac5805 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/createHttpServer.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/http/createHttpServer.ts @@ -16,7 +16,6 @@ import * as http from 'http'; import * as https from 'https'; -import stoppableServer from 'stoppable'; import { RequestListener } from 'http'; import { LoggerService } from '@backstage/backend-plugin-api'; import { HttpServerOptions, ExtendedHttpServer } from './types'; @@ -33,13 +32,6 @@ export async function createHttpServer( deps: { logger: LoggerService }, ): Promise { const server = await createServer(listener, options, deps); - - const stopper = stoppableServer(server, 0); - // The stopper here is actually the server itself, so if we try - // to call stopper.stop() down in the stop implementation, we'll - // be calling ourselves. - const stopServer = stopper.stop.bind(stopper); - return Object.assign(server, { start() { return new Promise((resolve, reject) => { @@ -61,7 +53,13 @@ export async function createHttpServer( stop() { return new Promise((resolve, reject) => { - stopServer((error?: Error) => { + if (process.env.NODE_ENV === 'development') { + // Ensure that various polling connections are shut down fast in development + server.closeAllConnections(); + } else { + server.closeIdleConnections(); + } + server.close(error => { if (error) { reject(error); } else { diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts index dea0159dff..0f2b6463e4 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.test.ts @@ -21,17 +21,207 @@ import { import { Express } from 'express'; import request from 'supertest'; import { rootHttpRouterServiceFactory } from './rootHttpRouterServiceFactory'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + ServiceFactory, + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; +import { BackendLifecycleImpl } from '../rootLifecycle/rootLifecycleServiceFactory'; + +async function createExpressApp(...dependencies: ServiceFactory[]) { + let app: Express | undefined = undefined; + + const tester = ServiceFactoryTester.from( + rootHttpRouterServiceFactory({ + configure(options) { + options.applyDefaults(); + app = options.app; + }, + }), + { + dependencies, + }, + ); + + // Trigger creation of the http service, accessing the app instance through the configure callback + await tester.getSubject(); + + if (!app) { + throw new Error('App not yet created'); + } + + return { app, tester }; +} describe('rootHttpRouterServiceFactory', () => { it('should make the health endpoints available', async () => { + const { app, tester } = await createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + }, + }, + }), + ); + + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend has not started yet', + status: 'error', + }); + + const lifecycle = await tester.getService(coreServices.rootLifecycle); + + await (lifecycle as any).startup(); // Trigger startup by calling the private startup method + + await request(app).get('/.backstage/health/v1/readiness').expect(200, { + status: 'ok', + }); + + expect('test').toBe('test'); + }); + + it('should include custom headers for health endpoint', async () => { + const { app, tester } = await createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + health: { + headers: { + 'x-test-header': 'test', + }, + }, + }, + }, + }), + ); + + const lRes = await request(app).get('/.backstage/health/v1/liveness'); + + expect(lRes.status).toBe(200); + expect(lRes.get('x-test-header')).toBe('test'); + + const r1Res = await request(app).get('/.backstage/health/v1/readiness'); + + expect(r1Res.status).toBe(503); + expect(r1Res.get('x-test-header')).toBe('test'); + + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend has not started yet', + status: 'error', + }); + + const lifecycle = await tester.getService(coreServices.rootLifecycle); + + await (lifecycle as any).startup(); // Trigger startup by calling the private startup method + + const r2Res = await request(app).get('/.backstage/health/v1/readiness'); + + expect(r2Res.status).toBe(200); + expect(r2Res.get('x-test-header')).toBe('test'); + }); + + it('should reject invalid health headers config', async () => { + await expect( + createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + health: { + headers: 'not-an-object', + }, + }, + }, + }), + ), + ).rejects.toThrow( + "Invalid type in config for key 'backend.health.headers' in 'mock-config', got string, wanted object", + ); + + await expect( + createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + health: { + headers: [], + }, + }, + }, + }), + ), + ).rejects.toThrow( + "Invalid type in config for key 'backend.health.headers' in 'mock-config', got array, wanted object", + ); + + await expect( + createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + health: { + headers: { + 'invalid-header': {}, + }, + }, + }, + }, + }), + ), + ).rejects.toThrow( + 'Invalid header value in at backend.health.headers, must be a non-empty string', + ); + + await expect( + createExpressApp( + mockServices.rootConfig.factory({ + data: { + backend: { + listen: { port: 0 }, + health: { + headers: { + 'invalid-header': '', + }, + }, + }, + }, + }), + ), + ).rejects.toThrow( + 'Invalid header value in at backend.health.headers, must be a non-empty string', + ); + }); + + it('should wait the server to shutdown', async () => { + jest.useFakeTimers(); + + const serverStopMock = jest.fn(); + let app: Express | undefined = undefined; + const lifecycleMock = new BackendLifecycleImpl(mockServices.rootLogger()); const tester = ServiceFactoryTester.from( rootHttpRouterServiceFactory({ configure(options) { - options.applyDefaults(); + options.app.use(options.healthRouter); + options.app.get('/test', (_req, res) => { + res.status(200).send({ status: 'ok' }).end(); + }); + options.app.use(options.middleware.error()); app = options.app; + options.server.addListener('close', serverStopMock); }, }), { @@ -42,33 +232,95 @@ describe('rootHttpRouterServiceFactory', () => { backend: { baseUrl: 'http://localhost', listen: { host: '', port: 0 }, + lifecycle: { + serverShutdownDelay: '30s', + }, }, }, }), + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory() { + return lifecycleMock; + }, + }), ], }, ); - // Trigger creation of the http service, accessing the app instance through the configure callback await tester.getSubject(); - await request(app!) - .get('/.backstage/health/v1/liveness') - .expect(200, { status: 'ok' }); - - await request(app!).get('/.backstage/health/v1/readiness').expect(503, { - message: 'Backend has not started yet', - status: 'error', - }); - + // Trigger creation of the http service, accessing the app instance through the configure callback const lifecycle = await tester.getService(coreServices.rootLifecycle); await (lifecycle as any).startup(); // Trigger startup by calling the private startup method - await request(app!).get('/.backstage/health/v1/readiness').expect(200, { + await request(app!).get('/test').expect(200, { status: 'ok', }); - expect('test').toBe('test'); + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app).get('/.backstage/health/v1/readiness').expect(200, { + status: 'ok', + }); + + const beforeShutdownPromise = (lifecycle as any) + .beforeShutdown() + .then(() => { + return (lifecycle as any).shutdown(); + }); + + // Continue accepting requests + await request(app!).get('/test').expect(200, { + status: 'ok', + }); + + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + // Immediately start failing the readiness health check + await request(app).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend is shuttting down', + status: 'error', + }); + + jest.advanceTimersByTime(29999); + + // Still accepting requests 1 ms before shutdown + await request(app!).get('/test').expect(200, { + status: 'ok', + }); + + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend is shuttting down', + status: 'error', + }); + + jest.advanceTimersByTime(1); + + await request(app) + .get('/.backstage/health/v1/liveness') + .expect(200, { status: 'ok' }); + + await request(app).get('/.backstage/health/v1/readiness').expect(503, { + message: 'Backend is shuttting down', + status: 'error', + }); + + return expect( + beforeShutdownPromise.then(() => { + expect(serverStopMock).toHaveBeenCalled(); + jest.useRealTimers(); + }), + ).resolves.toBeUndefined(); }); }); diff --git a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts index 59811c15d4..e5c64124fd 100644 --- a/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootHttpRouter/rootHttpRouterServiceFactory.ts @@ -30,6 +30,8 @@ import { } from './http'; import { DefaultRootHttpRouter } from './DefaultRootHttpRouter'; import { createHealthRouter } from './createHealthRouter'; +import { durationToMilliseconds } from '@backstage/types'; +import { readDurationFromConfig } from '@backstage/config'; /** * @public @@ -89,7 +91,8 @@ const rootHttpRouterServiceFactoryWithOptions = ( const middleware = MiddlewareFactory.create({ config, logger }); const routes = router.handler(); - const healthRouter = createHealthRouter({ health }); + const healthRouter = createHealthRouter({ config, health }); + const server = await createHttpServer( app, readHttpServerOptions(config.getOptionalConfig('backend')), @@ -120,6 +123,18 @@ const rootHttpRouterServiceFactoryWithOptions = ( }, }); + if (config.has('backend.lifecycle.serverShutdownDelay')) { + const serverShutdownDelay = readDurationFromConfig(config, { + key: 'backend.lifecycle.serverShutdownDelay', + }); + lifecycle.addBeforeShutdownHook(async () => { + const timeoutMs = durationToMilliseconds(serverShutdownDelay); + return await new Promise(resolve => { + setTimeout(resolve, timeoutMs); + }); + }); + } + lifecycle.addShutdownHook(() => server.stop()); await server.start(); diff --git a/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts index e724c2f5cb..abba4beece 100644 --- a/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts +++ b/packages/backend-defaults/src/entrypoints/rootLifecycle/rootLifecycleServiceFactory.ts @@ -65,6 +65,39 @@ export class BackendLifecycleImpl implements RootLifecycleService { ); } + #hasBeforeShutdown = false; + #beforeShutdownTasks: Array<{ hook: () => void | Promise }> = []; + + addBeforeShutdownHook(hook: () => void): void { + if (this.#hasBeforeShutdown) { + throw new Error( + 'Attempt to add before shutdown hook after shutdown has started', + ); + } + this.#beforeShutdownTasks.push({ hook }); + } + + async beforeShutdown(): Promise { + if (this.#hasBeforeShutdown) { + return; + } + this.#hasBeforeShutdown = true; + + this.logger.debug( + `Running ${this.#beforeShutdownTasks.length} before shutdown tasks...`, + ); + await Promise.all( + this.#beforeShutdownTasks.map(async ({ hook }) => { + try { + await hook(); + this.logger.debug(`Before shutdown hook succeeded`); + } catch (error) { + this.logger.error(`Before shutdown hook failed, ${error}`); + } + }), + ); + } + #hasShutdown = false; #shutdownTasks: Array<{ hook: LifecycleServiceShutdownHook; diff --git a/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.test.ts b/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.test.ts index 0f9e079943..ec46f22759 100644 --- a/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.test.ts +++ b/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.test.ts @@ -93,4 +93,28 @@ describe('WinstonLogger', () => { expect.any(Function), ); }); + + it('gracefully handles fields that are not castable to a string', () => { + const mockTransport = new Transport({ + log: jest.fn(), + logv: jest.fn(), + }); + + const logger = WinstonLogger.create({ + transports: [mockTransport], + }); + + logger.error('something went wrong', { + field: Object.create(null), + }); + + expect(mockTransport.log).toHaveBeenCalledWith( + expect.objectContaining({ + [MESSAGE]: expect.stringContaining( + '[field value not castable to string]', + ), + }), + expect.any(Function), + ); + }); }); diff --git a/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.ts b/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.ts index 38d05f6511..9f7532e66b 100644 --- a/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.ts +++ b/packages/backend-defaults/src/entrypoints/rootLogger/WinstonLogger.ts @@ -147,10 +147,17 @@ export class WinstonLogger implements RootLoggerService { const prefixColor = colorizer.colorize('prefix', prefix); const extraFields = Object.entries(fields) - .map( - ([key, value]) => - `${colorizer.colorize('field', `${key}`)}=${value}`, - ) + .map(([key, value]) => { + let stringValue = ''; + + try { + stringValue = `${value}`; + } catch (e) { + stringValue = '[field value not castable to string]'; + } + + return `${colorizer.colorize('field', `${key}`)}=${stringValue}`; + }) .join(' '); return `${timestampColor} ${prefixColor} ${level} ${message} ${extraFields}`; diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts index 3c641feadf..1ce1401829 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.test.ts @@ -55,7 +55,11 @@ describe('PluginTaskManagerImpl', () => { const manager = new PluginTaskSchedulerImpl( async () => knex, mockServices.logger.mock(), - { addShutdownHook, addStartupHook: jest.fn() }, + { + addShutdownHook, + addBeforeShutdownHook: jest.fn(), + addStartupHook: jest.fn(), + }, ); return { knex, manager }; } diff --git a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts index 5c04521149..ce1ff823cf 100644 --- a/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts +++ b/packages/backend-defaults/src/entrypoints/scheduler/lib/PluginTaskSchedulerImpl.ts @@ -24,7 +24,7 @@ import { SchedulerServiceTaskRunner, SchedulerServiceTaskScheduleDefinition, } from '@backstage/backend-plugin-api'; -import { Counter, Histogram, metrics, trace } from '@opentelemetry/api'; +import { Counter, Histogram, Gauge, metrics, trace } from '@opentelemetry/api'; import { Knex } from 'knex'; import { Duration } from 'luxon'; import { LocalTaskWorker } from './LocalTaskWorker'; @@ -44,6 +44,8 @@ export class PluginTaskSchedulerImpl implements SchedulerService { private readonly counter: Counter; private readonly duration: Histogram; + private readonly lastStarted: Gauge; + private readonly lastCompleted: Gauge; constructor( private readonly databaseFactory: () => Promise, @@ -58,6 +60,17 @@ export class PluginTaskSchedulerImpl implements SchedulerService { description: 'Histogram of task run durations', unit: 'seconds', }); + this.lastStarted = meter.createGauge('backend_tasks.task.runs.started', { + description: 'Epoch timestamp seconds when the task was last started', + unit: 'seconds', + }); + this.lastCompleted = meter.createGauge( + 'backend_tasks.task.runs.completed', + { + description: 'Epoch timestamp seconds when the task was last completed', + unit: 'seconds', + }, + ); this.shutdownInitiated = new Promise(shutdownInitiated => { rootLifecycle?.addShutdownHook(() => shutdownInitiated(true)); }); @@ -144,6 +157,7 @@ export class PluginTaskSchedulerImpl implements SchedulerService { scope, }; this.counter.add(1, { ...labels, result: 'started' }); + this.lastStarted.record(Date.now() / 1000, { taskId: task.id }); const startTime = process.hrtime(); @@ -170,6 +184,7 @@ export class PluginTaskSchedulerImpl implements SchedulerService { const endTime = delta[0] + delta[1] / 1e9; this.counter.add(1, labels); this.duration.record(endTime, labels); + this.lastCompleted.record(Date.now() / 1000, labels); } }; } diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts new file mode 100644 index 0000000000..e04e2c5b47 --- /dev/null +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureBlobStorageUrlReader.ts @@ -0,0 +1,235 @@ +/* + * 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 { + BlobDownloadOptions, + BlobServiceClient, + ContainerClient, + StorageSharedKeyCredential, +} from '@azure/storage-blob'; +import { ReaderFactory, ReadTreeResponseFactory } from './types'; +import { ForwardedError, NotModifiedError } from '@backstage/errors'; +import { Readable } from 'stream'; +import { relative } from 'path/posix'; +import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; +import { + AzureBlobStorageIntergation, + AzureCredentialsManager, + DefaultAzureCredentialsManager, + ScmIntegrations, +} from '@backstage/integration'; +import { + UrlReaderService, + UrlReaderServiceReadTreeOptions, + UrlReaderServiceReadTreeResponse, + UrlReaderServiceReadUrlOptions, + UrlReaderServiceReadUrlResponse, + UrlReaderServiceSearchResponse, +} from '@backstage/backend-plugin-api'; + +export function parseUrl(url: string): { path: string; container: string } { + const parsedUrl = new URL(url); + const pathSegments = parsedUrl.pathname.split('/').filter(Boolean); + + if (pathSegments.length < 1) { + throw new Error(`Invalid Azure Blob Storage URL format: ${url}`); + } + + // First segment is the container name, rest is the blob path + const container = pathSegments[0]; + const path = pathSegments.slice(1).join('/'); + + return { path, container }; +} + +/** + * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for Azure storage accounts urls. + * + * @public + */ +export class AzureBlobStorageUrlReader implements UrlReaderService { + static factory: ReaderFactory = ({ config, treeResponseFactory }) => { + const integrations = ScmIntegrations.fromConfig(config); + + const credsManager = + DefaultAzureCredentialsManager.fromIntegrations(integrations); + + return integrations.azureBlobStorage.list().map(integrationConfig => { + const reader = new AzureBlobStorageUrlReader( + credsManager, + integrationConfig, + { + treeResponseFactory, + }, + ); + + const predicate = (url: URL) => + url.host.endsWith( + `${integrationConfig.config.accountName}.${integrationConfig.config.host}`, + ); + return { reader, predicate }; + }); + }; + + // private readonly blobServiceClient: BlobServiceClient; + + constructor( + private readonly credsManager: AzureCredentialsManager, + private readonly integration: AzureBlobStorageIntergation, + private readonly deps: { + treeResponseFactory: ReadTreeResponseFactory; + }, + ) {} + + private async createContainerClient( + containerName: string, + ): Promise { + const accountName = this.integration.config.accountName; // Use the account name from the integration config + const accountKey = this.integration.config.accountKey; // Get the account key if it exists + + if (accountKey && accountName) { + const creds = new StorageSharedKeyCredential(accountName, accountKey); + const blobServiceClient = new BlobServiceClient( + `https://${accountName}.${this.integration.config.host}`, + creds, + ); + return blobServiceClient.getContainerClient(containerName); + } + // Use the credentials manager to get the correct credentials + const credential = await this.credsManager.getCredentials( + accountName as string, + ); + + let blobServiceClientUrl: string; + + if (this.integration.config.endpoint) { + if (this.integration.config.sasToken) { + blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`; + } else { + blobServiceClientUrl = `${this.integration.config.endpoint}`; + } + } else { + blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`; + } + + const blobServiceClient = new BlobServiceClient( + blobServiceClientUrl, + credential, + ); + return blobServiceClient.getContainerClient(containerName); + } + + async read(url: string): Promise { + const response = await this.readUrl(url); + return response.buffer(); + } + + async readUrl( + url: string, + options?: UrlReaderServiceReadUrlOptions, + ): Promise { + const { etag, lastModifiedAfter } = options ?? {}; + + try { + const { path, container } = parseUrl(url); + + const containerClient = await this.createContainerClient(container); + const blobClient = containerClient.getBlobClient(path); + + const getBlobOptions: BlobDownloadOptions = { + abortSignal: options?.signal, + conditions: { + ...(etag && { ifNoneMatch: etag }), + ...(lastModifiedAfter && { ifModifiedSince: lastModifiedAfter }), + }, + }; + + const downloadBlockBlobResponse = await blobClient.download( + 0, + undefined, + getBlobOptions, + ); + + return ReadUrlResponseFactory.fromReadable( + downloadBlockBlobResponse.readableStreamBody as Readable, + { + etag: downloadBlockBlobResponse.etag, + lastModifiedAt: downloadBlockBlobResponse.lastModified, + }, + ); + } catch (e) { + if (e.statusCode === 304) { + throw new NotModifiedError(); + } + + throw new ForwardedError( + 'Could not retrieve file from Azure Blob Storage', + e, + ); + } + } + + async readTree( + url: string, + options?: UrlReaderServiceReadTreeOptions, + ): Promise { + try { + const { path, container } = parseUrl(url); + + const containerClient = await this.createContainerClient(container); + + const blobs = containerClient.listBlobsFlat({ prefix: path }); + + const responses = []; + + for await (const blob of blobs) { + const blobClient = containerClient.getBlobClient(blob.name); + const downloadBlockBlobResponse = await blobClient.download( + undefined, + undefined, + { abortSignal: options?.signal }, + ); + + responses.push({ + data: Readable.from( + downloadBlockBlobResponse.readableStreamBody as Readable, + ), + path: relative(path, blob.name), + lastModifiedAt: blob.properties.lastModified, + }); + } + + return this.deps.treeResponseFactory.fromReadableArray(responses); + } catch (e) { + throw new ForwardedError( + 'Could not retrieve file tree from Azure Blob Storage', + e, + ); + } + } + + async search(): Promise { + throw new Error('AzureBlobStorageUrlReader does not implement search'); + } + + toString() { + const accountName = this.integration.config.accountName; + const accountKey = this.integration.config.accountKey; + return `azureBlobStorage{accountName=${accountName},authed=${Boolean( + accountKey, + )}}`; + } +} diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.ts index 50513fcdcc..b46e7c20cd 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/AzureUrlReader.ts @@ -32,9 +32,7 @@ import { ScmIntegrations, AzureIntegration, } from '@backstage/integration'; -import fetch, { Response } from 'node-fetch'; import { Minimatch } from 'minimatch'; -import { Readable } from 'stream'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; import { ReadTreeResponseFactory, ReaderFactory } from './types'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; @@ -101,7 +99,7 @@ export class AzureUrlReader implements UrlReaderService { // for private repos when PAT is not valid, Azure API returns a http status code 203 with sign in page html if (response.ok && response.status !== 203) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body); + return ReadUrlResponseFactory.fromResponse(response); } const message = `${url} could not be read as ${builtUrl}, ${response.status} ${response.statusText}`; @@ -172,7 +170,7 @@ export class AzureUrlReader implements UrlReaderService { } return await this.deps.treeResponseFactory.fromZipArchive({ - stream: Readable.from(archiveAzureResponse.body), + response: archiveAzureResponse, etag: commitSha, filter, subpath, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts index b7b733867e..f6742c7423 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketCloudUrlReader.ts @@ -32,14 +32,11 @@ import { getBitbucketCloudRequestOptions, ScmIntegrations, } from '@backstage/integration'; -import fetch, { Response } from 'node-fetch'; import parseGitUrl from 'git-url-parse'; import { trimEnd } from 'lodash'; import { Minimatch } from 'minimatch'; -import { Readable } from 'stream'; import { ReaderFactory, ReadTreeResponseFactory } from './types'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; -import { parseLastModified } from './util'; /** * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Cloud. @@ -116,12 +113,7 @@ export class BitbucketCloudUrlReader implements UrlReaderService { } if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); + return ReadUrlResponseFactory.fromResponse(response); } const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`; @@ -159,7 +151,7 @@ export class BitbucketCloudUrlReader implements UrlReaderService { } return await this.deps.treeResponseFactory.fromTarArchive({ - stream: Readable.from(archiveResponse.body), + response: archiveResponse, subpath: filepath, etag: lastCommitShortHash, filter: options?.filter, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.ts index 332e300cb8..d327f80704 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketServerUrlReader.ts @@ -31,14 +31,25 @@ import { getBitbucketServerRequestOptions, ScmIntegrations, } from '@backstage/integration'; -import fetch, { Response } from 'node-fetch'; import parseGitUrl from 'git-url-parse'; import { trimEnd } from 'lodash'; import { Minimatch } from 'minimatch'; -import { Readable } from 'stream'; import { ReaderFactory, ReadTreeResponseFactory } from './types'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; -import { parseLastModified } from './util'; + +import pThrottle from 'p-throttle'; + +// 1 per second +const throttle = pThrottle({ + limit: 1, + interval: 1000, +}); + +const throttledFetch = throttle( + async (url: RequestInfo, options?: RequestInit) => { + return await fetch(url, options); + }, +); /** * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket Server APIs. @@ -82,7 +93,7 @@ export class BitbucketServerUrlReader implements UrlReaderService { let response: Response; try { - response = await fetch(bitbucketUrl.toString(), { + response = await throttledFetch(bitbucketUrl.toString(), { headers: { ...requestOptions.headers, ...(etag && { 'If-None-Match': etag }), @@ -107,12 +118,7 @@ export class BitbucketServerUrlReader implements UrlReaderService { } if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); + return ReadUrlResponseFactory.fromResponse(response); } const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`; @@ -137,7 +143,7 @@ export class BitbucketServerUrlReader implements UrlReaderService { url, this.integration.config, ); - const archiveResponse = await fetch( + const archiveResponse = await throttledFetch( downloadUrl, getBitbucketServerRequestOptions(this.integration.config), ); @@ -150,7 +156,7 @@ export class BitbucketServerUrlReader implements UrlReaderService { } return await this.deps.treeResponseFactory.fromTarArchive({ - stream: Readable.from(archiveResponse.body), + response: archiveResponse, subpath: filepath, etag: lastCommitShortHash, filter: options?.filter, @@ -206,7 +212,7 @@ export class BitbucketServerUrlReader implements UrlReaderService { // https://docs.atlassian.com/bitbucket-server/rest/7.9.0/bitbucket-rest.html#idp211 (branches docs) const branchListUrl = `${this.integration.config.apiBaseUrl}/projects/${project}/repos/${repoName}/branches${branchParameter}`; - const branchListResponse = await fetch( + const branchListResponse = await throttledFetch( branchListUrl, getBitbucketServerRequestOptions(this.integration.config), ); diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.ts index 55d676ed91..c12998509e 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/BitbucketUrlReader.ts @@ -32,15 +32,12 @@ import { getBitbucketRequestOptions, ScmIntegrations, } from '@backstage/integration'; -import fetch, { Response } from 'node-fetch'; import parseGitUrl from 'git-url-parse'; import { trimEnd } from 'lodash'; import { Minimatch } from 'minimatch'; -import { Readable } from 'stream'; import { LoggerService } from '@backstage/backend-plugin-api'; import { ReaderFactory, ReadTreeResponseFactory } from './types'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; -import { parseLastModified } from './util'; /** * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files from Bitbucket v1 and v2 APIs, such @@ -127,12 +124,7 @@ export class BitbucketUrlReader implements UrlReaderService { } if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); + return ReadUrlResponseFactory.fromResponse(response); } const message = `${url} could not be read as ${bitbucketUrl}, ${response.status} ${response.statusText}`; @@ -170,7 +162,7 @@ export class BitbucketUrlReader implements UrlReaderService { } return await this.deps.treeResponseFactory.fromTarArchive({ - stream: Readable.from(archiveBitbucketResponse.body), + response: archiveBitbucketResponse, subpath: filepath, etag: lastCommitShortHash, filter: options?.filter, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.ts index 55041cf036..0e5a279c4d 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/FetchUrlReader.ts @@ -22,11 +22,9 @@ import { UrlReaderServiceSearchResponse, } from '@backstage/backend-plugin-api'; import { NotFoundError, NotModifiedError } from '@backstage/errors'; -import fetch, { Response } from 'node-fetch'; import { ReaderFactory } from './types'; import path from 'path'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; -import { parseLastModified } from './util'; const isInRange = (num: number, [start, end]: [number, number]) => { return num >= start && num <= end; @@ -150,12 +148,7 @@ export class FetchUrlReader implements UrlReaderService { } if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); + return ReadUrlResponseFactory.fromResponse(response); } const message = `could not read ${url}, ${response.status} ${response.statusText}`; diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.ts index d8471c43f3..502c2d2ff9 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GiteaUrlReader.ts @@ -32,7 +32,6 @@ import { ScmIntegrations, } from '@backstage/integration'; import { ReaderFactory, ReadTreeResponseFactory } from './types'; -import fetch, { Response } from 'node-fetch'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; import { AuthenticationError, @@ -149,7 +148,7 @@ export class GiteaUrlReader implements UrlReaderService { const parsedUri = parseGiteaUrl(this.integration.config, url); return this.deps.treeResponseFactory.fromTarArchive({ - stream: Readable.from(response.body), + response: response, subpath: parsedUri.path, etag: lastCommitHash, filter: options?.filter, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts index f5050cca5e..c1d8c02a53 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/GitlabUrlReader.ts @@ -34,11 +34,8 @@ import { import parseGitUrl from 'git-url-parse'; import { trimEnd, trimStart } from 'lodash'; import { Minimatch } from 'minimatch'; -import fetch, { Response } from 'node-fetch'; -import { Readable } from 'stream'; import { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; import { ReadTreeResponseFactory, ReaderFactory } from './types'; -import { parseLastModified } from './util'; /** * Implements a {@link @backstage/backend-plugin-api#UrlReaderService} for files on GitLab. @@ -101,12 +98,7 @@ export class GitlabUrlReader implements UrlReaderService { } if (response.ok) { - return ReadUrlResponseFactory.fromNodeJSReadable(response.body, { - etag: response.headers.get('ETag') ?? undefined, - lastModifiedAt: parseLastModified( - response.headers.get('Last-Modified'), - ), - }); + return ReadUrlResponseFactory.fromResponse(response); } const message = `${url} could not be read as ${builtUrl}, ${response.status} ${response.statusText}`; @@ -228,7 +220,7 @@ export class GitlabUrlReader implements UrlReaderService { } return await this.deps.treeResponseFactory.fromTarArchive({ - stream: Readable.from(archiveGitLabResponse.body), + response: archiveGitLabResponse, subpath: filepath, etag: commitSha, filter: options?.filter, diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts index ecc1bd6101..1f4f297c5a 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/ReadUrlResponseFactory.ts @@ -19,6 +19,7 @@ import { UrlReaderServiceReadUrlResponse } from '@backstage/backend-plugin-api'; import getRawBody from 'raw-body'; import { Readable } from 'stream'; import { ReadUrlResponseFactoryFromStreamOptions } from './types'; +import { parseLastModified, responseToReadable } from './util'; /** * Utility class for UrlReader implementations to create valid ReadUrlResponse @@ -28,7 +29,7 @@ import { ReadUrlResponseFactoryFromStreamOptions } from './types'; */ export class ReadUrlResponseFactory { /** - * Resolves a ReadUrlResponse from a Readable stream. + * Resolves a UrlReaderServiceReadUrlResponse from a Readable stream. */ static async fromReadable( stream: Readable, @@ -64,7 +65,7 @@ export class ReadUrlResponseFactory { } /** - * Resolves a ReadUrlResponse from an old-style NodeJS.ReadableStream. + * Resolves a UrlReaderServiceReadUrlResponse from an old-style NodeJS.ReadableStream. */ static async fromNodeJSReadable( oldStyleStream: NodeJS.ReadableStream, @@ -73,4 +74,21 @@ export class ReadUrlResponseFactory { const readable = Readable.from(oldStyleStream); return ReadUrlResponseFactory.fromReadable(readable, options); } + + /** + * Resolves a UrlReaderServiceReadUrlResponse from a native fetch response body. + */ + static async fromResponse( + response: Response, + ): Promise { + const etag = response.headers.get('etag') || undefined; + const lastModifiedAt = parseLastModified( + response.headers.get('last-modified'), + ); + + return ReadUrlResponseFactory.fromReadable(responseToReadable(response), { + etag, + lastModifiedAt, + }); + } } diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/UrlReaders.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/UrlReaders.ts index 96e9ed6509..229bdd4903 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/UrlReaders.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/UrlReaders.ts @@ -35,6 +35,7 @@ import { AwsS3UrlReader } from './AwsS3UrlReader'; import { GiteaUrlReader } from './GiteaUrlReader'; import { AwsCodeCommitUrlReader } from './AwsCodeCommitUrlReader'; import { HarnessUrlReader } from './HarnessUrlReader'; +import { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader'; /** * Creation options for {@link @backstage/backend-plugin-api#UrlReaderService}. @@ -99,6 +100,7 @@ export class UrlReaders { GoogleGcsUrlReader.factory, HarnessUrlReader.factory, AwsS3UrlReader.factory, + AzureBlobStorageUrlReader.factory, AwsCodeCommitUrlReader.factory, FetchUrlReader.factory, ]), diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/index.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/index.ts index 678c6ef64b..fc33efbc3a 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/index.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/index.ts @@ -24,6 +24,7 @@ export { GitlabUrlReader } from './GitlabUrlReader'; export { GiteaUrlReader } from './GiteaUrlReader'; export { HarnessUrlReader } from './HarnessUrlReader'; export { AwsS3UrlReader } from './AwsS3UrlReader'; +export { AzureBlobStorageUrlReader } from './AzureBlobStorageUrlReader'; export { FetchUrlReader } from './FetchUrlReader'; export { ReadUrlResponseFactory } from './ReadUrlResponseFactory'; export type { diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.ts index 1973b2158f..a8f187d7b8 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/tree/ReadTreeResponseFactory.ts @@ -15,6 +15,7 @@ */ import os from 'os'; +import { Readable } from 'stream'; import { Config } from '@backstage/config'; import { ReadTreeResponseFactoryOptions, @@ -25,6 +26,7 @@ import { TarArchiveResponse } from './TarArchiveResponse'; import { ZipArchiveResponse } from './ZipArchiveResponse'; import { ReadableArrayResponse } from './ReadableArrayResponse'; import { UrlReaderServiceReadTreeResponse } from '@backstage/backend-plugin-api'; +import { responseToReadable } from '../util'; export class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory { static create(options: { config: Config }): DefaultReadTreeResponseFactory { @@ -41,11 +43,21 @@ export class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory { stripFirstDirectory?: boolean; }, ): Promise { + let stream: Readable; + let etag: string; + if ('stream' in options) { + stream = options.stream; + etag = options.etag; + } else { + stream = responseToReadable(options.response); + etag = (options.etag ?? options.response.headers.get('etag')) || ''; + } + return new TarArchiveResponse( - options.stream, + stream, options.subpath ?? '', this.workDir, - options.etag, + etag, options.filter, options.stripFirstDirectory ?? true, ); @@ -54,11 +66,21 @@ export class DefaultReadTreeResponseFactory implements ReadTreeResponseFactory { async fromZipArchive( options: ReadTreeResponseFactoryOptions, ): Promise { + let stream: Readable; + let etag: string; + if ('stream' in options) { + stream = options.stream; + etag = options.etag; + } else { + stream = responseToReadable(options.response); + etag = (options.etag ?? options.response.headers.get('etag')) || ''; + } + return new ZipArchiveResponse( - options.stream, + stream, options.subpath ?? '', this.workDir, - options.etag, + etag, options.filter, ); } diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/types.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/types.ts index 5afbed178f..f8f03a6f3b 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/types.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/types.ts @@ -60,17 +60,28 @@ export type ReadUrlResponseFactoryFromStreamOptions = { * * @public */ -export type ReadTreeResponseFactoryOptions = { - // A binary stream of a tar archive. - stream: Readable; - // If unset, the files at the root of the tree will be read. - // subpath must not contain the name of the top level directory. - subpath?: string; - // etag of the blob - etag: string; - // Filter passed on from the ReadTreeOptions - filter?: (path: string, info?: { size: number }) => boolean; -}; +export type ReadTreeResponseFactoryOptions = + | { + // A binary stream of a tar archive. + stream: Readable; + // If unset, the files at the root of the tree will be read. + // subpath must not contain the name of the top level directory. + subpath?: string; + // etag of the blob + etag: string; + // Filter passed on from the ReadTreeOptions + filter?: (path: string, info?: { size: number }) => boolean; + } + | { + /** A response from a fetch request */ + response: Response; + /** If unset, the files at the root of the tree will be read. Subpath must not contain the name of the top level directory. */ + subpath?: string; + /** etag of the blob, to optionally override what the response header may or may not say */ + etag?: string; + /** Filter passed on from the ReadTreeOptions */ + filter?: (path: string, info?: { size: number }) => boolean; + }; /** * Options that control {@link ReadTreeResponseFactory.fromReadableArray} diff --git a/packages/backend-defaults/src/entrypoints/urlReader/lib/util.ts b/packages/backend-defaults/src/entrypoints/urlReader/lib/util.ts index 3d65c2c527..bd19feef2d 100644 --- a/packages/backend-defaults/src/entrypoints/urlReader/lib/util.ts +++ b/packages/backend-defaults/src/entrypoints/urlReader/lib/util.ts @@ -14,10 +14,47 @@ * limitations under the License. */ -export function parseLastModified(value: string | null | undefined) { +import { PassThrough, Readable } from 'stream'; +import { ReadableStream as WebReadableStream } from 'stream/web'; + +export function parseLastModified( + value: string | null | undefined, +): Date | undefined { if (!value) { return undefined; } - return new Date(value); + try { + const result = new Date(value); + result.toISOString(); // triggers exception if input was invalid + return result; + } catch { + return undefined; + } +} + +export function responseToReadable(response: Response): Readable { + return response.body + ? Readable.from(toWeb(response.body)) + : new PassThrough().end(); +} + +// The NodeJS ReadableStream is that fetch returns is super basic and not even +// iterable. This function converts it to the smarter, iterable stream/web +// variant instead. +export function toWeb( + responseBody: ReadableStream, +): WebReadableStream { + const reader = responseBody.getReader(); + return new WebReadableStream({ + async pull(controller) { + const { value, done } = await reader.read(); + if (value) { + controller.enqueue(value); + } + if (done) { + controller.close(); + } + }, + }); } diff --git a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.ts b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.ts index 83bbba89b7..21f8de5631 100644 --- a/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.ts +++ b/packages/backend-defaults/src/entrypoints/userInfo/DefaultUserInfoService.ts @@ -22,7 +22,6 @@ import { } from '@backstage/backend-plugin-api'; import { ResponseError } from '@backstage/errors'; import { decodeJwt } from 'jose'; -import fetch from 'node-fetch'; import { toInternalBackstageCredentials } from '../auth/helpers'; export type Options = { diff --git a/packages/backend-dynamic-feature-service/CHANGELOG.md b/packages/backend-dynamic-feature-service/CHANGELOG.md index 290db959be..d01ee9ab5c 100644 --- a/packages/backend-dynamic-feature-service/CHANGELOG.md +++ b/packages/backend-dynamic-feature-service/CHANGELOG.md @@ -1,5 +1,119 @@ # @backstage/backend-dynamic-feature-service +## 0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-app-node@0.1.28-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.5.0 + +### Minor Changes + +- e939cd7: **BREAKING** The `dynamicPluginsFeatureLoader` options related to the root logger behavior (`transports`, `level`, `format`) are now gathered under a single `logger` option which is a function taking an optional `Config` argument and returning the logger options. + + This breaking change is required for 2 reasons: + + - it's totally possible that the current `Config` would be required to provide the logger options, + - the logger-related options should be gathered under a common `logger` option because, when the root auditing service is introduced, distinct but similarly-named options would be required for the auditor as well. + +### Patch Changes + +- 1aeec12: Enhance the `CommonJSModuleLoader` to add support for `resolvePackagePath` calls from backend dynamic plugins, with customizable package resolution, and make the `CommonJSModuleLoader` public API. + Fixing this backend dynamic plugin limitation related to `resolvePackagePath` is important for backend dynamic plugins which use the database, since database migration scripts systematically use `resolvePackagePath`. +- 8593dfa: Improve the way alpha packages are supported when loading dynamic backend plugins. + The `ScannedPluginPackage` descriptor of dynamic backend plugins loaded from their alpha `package.json` now contain both the main package manifest and the alpha manifest. Previously it used to contain only the content of the alpha `package.json`, which is nearly empty. + This will make it easier to use or display metadata of loaded dynamic backend plugins, which is contained in the main manifest. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/plugin-app-node@0.1.27 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-search-common@1.2.15 + ## 0.5.0-next.3 ### Patch Changes diff --git a/packages/backend-dynamic-feature-service/package.json b/packages/backend-dynamic-feature-service/package.json index a2047e1efe..cb34c886e7 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.5.0-next.3", + "version": "0.5.2-next.2", "description": "Backstage dynamic feature service", "backstage": { "role": "node-library" diff --git a/packages/backend-legacy/CHANGELOG.md b/packages/backend-legacy/CHANGELOG.md index 89475b83e5..2e5fdf3d48 100644 --- a/packages/backend-legacy/CHANGELOG.md +++ b/packages/backend-legacy/CHANGELOG.md @@ -1,5 +1,167 @@ # example-backend-legacy +## 0.2.105-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.28.0-next.2 + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-app-backend@0.4.3-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-kubernetes-backend@0.19.1-next.2 + - @backstage/plugin-proxy-backend@0.5.9-next.2 + - @backstage/plugin-search-backend@1.8.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-signals-backend@0.2.4-next.2 + - @backstage/plugin-techdocs-backend@1.11.4-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-permission-backend@0.5.52-next.2 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.2 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.2 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.2 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.2.105-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.1 + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-search-backend@1.8.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.1 + - @backstage/plugin-permission-backend@0.5.52-next.1 + - @backstage/plugin-techdocs-backend@1.11.4-next.1 + - @backstage/plugin-signals-backend@0.2.4-next.1 + - @backstage/plugin-proxy-backend@0.5.9-next.1 + - @backstage/plugin-app-backend@0.4.3-next.1 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.1 + - @backstage/plugin-kubernetes-backend@0.19.1-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-scaffolder-backend@1.28.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.1 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.4-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.1 + +## 0.2.105-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-backend@1.28.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.0 + - @backstage/plugin-app-backend@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-backend@0.5.52-next.0 + - @backstage/plugin-devtools-backend@0.4.3-next.0 + - @backstage/plugin-signals-backend@0.2.4-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/plugin-kubernetes-backend@0.19.1-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-auth-backend@0.24.1-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-proxy-backend@0.5.9-next.0 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.3-next.0 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.3-next.0 + - @backstage/plugin-search-backend@1.7.1-next.0 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.3-next.0 + - @backstage/plugin-search-backend-module-pg@0.5.39-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + - @backstage/plugin-techdocs-backend@1.11.4-next.0 + +## 0.2.104 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-app-backend@0.4.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-scaffolder-backend@1.27.0 + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-search-backend@1.7.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.6.1 + - @backstage/plugin-kubernetes-backend@0.19.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-search-backend-module-elasticsearch@1.6.2 + - @backstage/plugin-search-backend-module-explore@0.2.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-signals-backend@0.2.3 + - @backstage/plugin-search-backend-module-pg@0.5.38 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-proxy-backend@0.5.8 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/plugin-scaffolder-backend-module-rails@0.5.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.2 + - @backstage/plugin-devtools-backend@0.4.2 + - @backstage/plugin-permission-backend@0.5.51 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-confluence-to-markdown@0.3.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.2 + - @backstage/plugin-techdocs-backend@1.11.2 + ## 0.2.104-next.3 ### Patch Changes diff --git a/packages/backend-legacy/package.json b/packages/backend-legacy/package.json index 9f94bd30de..f1ac32e60b 100644 --- a/packages/backend-legacy/package.json +++ b/packages/backend-legacy/package.json @@ -1,6 +1,6 @@ { "name": "example-backend-legacy", - "version": "0.2.104-next.3", + "version": "0.2.105-next.2", "backstage": { "role": "backend" }, @@ -42,7 +42,6 @@ "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "@backstage/plugin-devtools-backend": "workspace:^", "@backstage/plugin-events-backend": "workspace:^", "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-kubernetes-backend": "workspace:^", diff --git a/packages/backend-legacy/src/index.ts b/packages/backend-legacy/src/index.ts index 23f71baba5..8ef969ff2b 100644 --- a/packages/backend-legacy/src/index.ts +++ b/packages/backend-legacy/src/index.ts @@ -48,7 +48,6 @@ import techdocs from './plugins/techdocs'; import app from './plugins/app'; import permission from './plugins/permission'; import signals from './plugins/signals'; -import devtools from './plugins/devtools'; import { PluginEnvironment } from './types'; import { ServerPermissionClient } from '@backstage/plugin-permission-node'; import { DefaultIdentityClient } from '@backstage/plugin-auth-node'; @@ -138,7 +137,6 @@ async function main() { const appEnv = useHotMemoize(module, () => createEnv('app')); const permissionEnv = useHotMemoize(module, () => createEnv('permission')); const eventsEnv = useHotMemoize(module, () => createEnv('events')); - const devToolsEnv = useHotMemoize(module, () => createEnv('devtools')); const signalsEnv = useHotMemoize(module, () => createEnv('signals')); const apiRouter = Router(); @@ -151,7 +149,6 @@ async function main() { apiRouter.use('/kubernetes', await kubernetes(kubernetesEnv)); apiRouter.use('/proxy', await proxy(proxyEnv)); apiRouter.use('/permission', await permission(permissionEnv)); - apiRouter.use('/devtools', await devtools(devToolsEnv)); apiRouter.use('/signals', await signals(signalsEnv)); apiRouter.use(notFoundHandler()); diff --git a/packages/backend-openapi-utils/CHANGELOG.md b/packages/backend-openapi-utils/CHANGELOG.md index dd268da771..35ec5cc456 100644 --- a/packages/backend-openapi-utils/CHANGELOG.md +++ b/packages/backend-openapi-utils/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/backend-openapi-utils +## 0.4.0-next.2 + +### Minor Changes + +- afcebea: Fixed a Typescript error when trying to use the new OpenAPI server-side generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## 0.3.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.0 + +### Minor Changes + +- 1440232: Adds a new `createValidatedOpenApiRouterFromGeneratedEndpointMap` function that uses the new static server generation in `backstage-cli package schema openapi generate --server` to create a typed express router. + +### Patch Changes + +- f01787a: Moves msw from dependencies to devDependencies +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.3.0-next.2 ### Minor Changes diff --git a/packages/backend-openapi-utils/README.md b/packages/backend-openapi-utils/README.md index 3d3f40682e..33f2200f81 100644 --- a/packages/backend-openapi-utils/README.md +++ b/packages/backend-openapi-utils/README.md @@ -1,4 +1,4 @@ -# @backstage/openapi-utils +# @backstage/backend-openapi-utils ## Summary diff --git a/packages/backend-openapi-utils/package.json b/packages/backend-openapi-utils/package.json index bb06c18740..099afe2419 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.3.0-next.2", + "version": "0.4.0-next.2", "description": "OpenAPI typescript support.", "backstage": { "role": "node-library" diff --git a/packages/backend-openapi-utils/report.api.md b/packages/backend-openapi-utils/report.api.md index 399705a9e4..22913eb321 100644 --- a/packages/backend-openapi-utils/report.api.md +++ b/packages/backend-openapi-utils/report.api.md @@ -530,7 +530,6 @@ declare namespace internal { DocEndpointTemplate, TemplateToDocEndpoint, EndpointMapRequestMatcher, - TypedRouter, }; } export { internal }; @@ -902,7 +901,8 @@ type TuplifyUnion< > = true extends N ? [] : Push>, L>; // @public (undocumented) -interface TypedRouter extends Router { +export interface TypedRouter + extends Router { // (undocumented) delete: EndpointMapRequestMatcher; // (undocumented) diff --git a/packages/backend-openapi-utils/src/index.ts b/packages/backend-openapi-utils/src/index.ts index a66894d473..9389fe3be6 100644 --- a/packages/backend-openapi-utils/src/index.ts +++ b/packages/backend-openapi-utils/src/index.ts @@ -30,7 +30,7 @@ export type { CookieParameters, PathParameters, } from './utility'; -export type { ApiRouter } from './router'; +export type { ApiRouter, TypedRouter } from './router'; export type { PathTemplate } from './types/common'; export { wrapInOpenApiTestServer, wrapServer } from './testUtils'; export { diff --git a/packages/backend-openapi-utils/src/router.ts b/packages/backend-openapi-utils/src/router.ts index 253fc1596e..48d89054ba 100644 --- a/packages/backend-openapi-utils/src/router.ts +++ b/packages/backend-openapi-utils/src/router.ts @@ -14,7 +14,12 @@ * limitations under the License. */ import { Router } from 'express'; -import { DocRequestMatcher, RequiredDoc } from './types'; +import { + DocRequestMatcher, + EndpointMap, + EndpointMapRequestMatcher, + RequiredDoc, +} from './types'; /** * Typed Express router based on an OpenAPI 3.1 spec. @@ -37,3 +42,14 @@ export interface ApiRouter extends Router { head: DocRequestMatcher; } + +/** + * @public + */ +export interface TypedRouter + extends Router { + get: EndpointMapRequestMatcher; + post: EndpointMapRequestMatcher; + put: EndpointMapRequestMatcher; + delete: EndpointMapRequestMatcher; +} diff --git a/packages/backend-openapi-utils/src/stub.ts b/packages/backend-openapi-utils/src/stub.ts index 615c32cb31..8ab00c4df4 100644 --- a/packages/backend-openapi-utils/src/stub.ts +++ b/packages/backend-openapi-utils/src/stub.ts @@ -15,8 +15,8 @@ */ import PromiseRouter from 'express-promise-router'; -import { ApiRouter } from './router'; -import { EndpointMap, RequiredDoc, TypedRouter } from './types'; +import { ApiRouter, TypedRouter } from './router'; +import { EndpointMap, RequiredDoc } from './types'; import { ErrorRequestHandler, RequestHandler, diff --git a/packages/backend-openapi-utils/src/types/generated.ts b/packages/backend-openapi-utils/src/types/generated.ts index b0b80f45fb..e4d5dada72 100644 --- a/packages/backend-openapi-utils/src/types/generated.ts +++ b/packages/backend-openapi-utils/src/types/generated.ts @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Router } from 'express'; import type core from 'express-serve-static-core'; import { PathTemplate, ValueOf } from './common'; @@ -209,14 +208,3 @@ export interface EndpointMapRequestMatcher< > ): T; } - -/** - * @public - */ -export interface TypedRouter - extends Router { - get: EndpointMapRequestMatcher; - post: EndpointMapRequestMatcher; - put: EndpointMapRequestMatcher; - delete: EndpointMapRequestMatcher; -} diff --git a/packages/backend-plugin-api/CHANGELOG.md b/packages/backend-plugin-api/CHANGELOG.md index 7aa27f59a0..13797bc63a 100644 --- a/packages/backend-plugin-api/CHANGELOG.md +++ b/packages/backend-plugin-api/CHANGELOG.md @@ -1,5 +1,63 @@ # @backstage/backend-plugin-api +## 1.1.0-next.2 + +### Patch Changes + +- 0e9c9fa: The `RootLifecycleService` now has a new `addBeforeShutdownHook` method, and hooks added through this method will run immediately when a termination event is received. + + The backend will not proceed with the shutdown and run the `Shutdown` hooks until all `BeforeShutdown` hooks have completed. + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.1.0-next.1 + +### Minor Changes + +- 12eac85: **EXPERIMENTAL**: Adds a new `instanceMetadataService` to hold information about a specific backend instance. + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## 1.0.3-next.0 + +### Patch Changes + +- eef3ef1: Removed unused `express` dependencies. +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## 1.0.2 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + ## 1.0.2-next.2 ### Patch Changes diff --git a/packages/backend-plugin-api/package.json b/packages/backend-plugin-api/package.json index 0bbab5a913..9bfae928c2 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.0.2-next.2", + "version": "1.1.0-next.2", "description": "Core API used by Backstage backend plugins", "backstage": { "role": "node-library" @@ -61,7 +61,6 @@ "@backstage/types": "workspace:^", "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", - "express": "^4.17.1", "knex": "^3.0.0", "luxon": "^3.0.0" }, diff --git a/packages/backend-plugin-api/report-alpha.api.md b/packages/backend-plugin-api/report-alpha.api.md index dea357502e..8509d1196d 100644 --- a/packages/backend-plugin-api/report-alpha.api.md +++ b/packages/backend-plugin-api/report-alpha.api.md @@ -6,6 +6,18 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { ServiceRef } from '@backstage/backend-plugin-api'; +// @alpha (undocumented) +export type BackendFeatureMeta = + | { + type: 'plugin'; + pluginId: string; + } + | { + type: 'module'; + pluginId: string; + moduleId: string; + }; + // @alpha (undocumented) export interface FeatureDiscoveryService { // (undocumented) @@ -21,5 +33,18 @@ export const featureDiscoveryServiceRef: ServiceRef< 'singleton' >; +// @alpha (undocumented) +export interface InstanceMetadataService { + // (undocumented) + getInstalledFeatures: () => BackendFeatureMeta[]; +} + +// @alpha +export const instanceMetadataServiceRef: ServiceRef< + InstanceMetadataService, + 'plugin', + 'singleton' +>; + // (No @packageDocumentation comment for this package) ``` diff --git a/packages/backend-plugin-api/report.api.md b/packages/backend-plugin-api/report.api.md index 89dfe40dd9..8416c6c200 100644 --- a/packages/backend-plugin-api/report.api.md +++ b/packages/backend-plugin-api/report.api.md @@ -10,7 +10,7 @@ import { AuthorizePermissionResponse } from '@backstage/plugin-permission-common import { Config } from '@backstage/config'; import { Duration } from 'luxon'; import { EvaluatorRequestOptions } from '@backstage/plugin-permission-common'; -import { Handler } from 'express'; +import type { Handler } from 'express'; import { HumanDuration } from '@backstage/types'; import { isChildPath } from '@backstage/cli-common'; import { JsonObject } from '@backstage/types'; @@ -21,8 +21,8 @@ import { PermissionEvaluator } from '@backstage/plugin-permission-common'; import { QueryPermissionRequest } from '@backstage/plugin-permission-common'; import { QueryPermissionResponse } from '@backstage/plugin-permission-common'; import { Readable } from 'stream'; -import { Request as Request_2 } from 'express'; -import { Response as Response_2 } from 'express'; +import type { Request as Request_2 } from 'express'; +import type { Response as Response_2 } from 'express'; // @public export interface AuthService { @@ -507,7 +507,10 @@ export interface RootHttpRouterService { } // @public -export interface RootLifecycleService extends LifecycleService {} +export interface RootLifecycleService extends LifecycleService { + // (undocumented) + addBeforeShutdownHook(hook: () => void | Promise): void; +} // @public export interface RootLoggerService extends LoggerService {} diff --git a/packages/backend-plugin-api/src/alpha.ts b/packages/backend-plugin-api/src/alpha.ts index 3f26c66fe9..1a39fe6c23 100644 --- a/packages/backend-plugin-api/src/alpha.ts +++ b/packages/backend-plugin-api/src/alpha.ts @@ -34,3 +34,19 @@ export const featureDiscoveryServiceRef = id: 'core.featureDiscovery', scope: 'root', }); + +/** + * 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'; diff --git a/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts b/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts index 718aa9b532..152bb205de 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpAuthService.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Request, Response } from 'express'; +import type { Request, Response } from 'express'; import { BackstageCredentials, BackstagePrincipalTypes } from './AuthService'; /** diff --git a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts index 92f7e950f9..529d7481f1 100644 --- a/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/HttpRouterService.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Handler } from 'express'; +import type { Handler } from 'express'; /** * Options for {@link HttpRouterService.addAuthPolicy}. diff --git a/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts b/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts new file mode 100644 index 0000000000..869d361343 --- /dev/null +++ b/packages/backend-plugin-api/src/services/definitions/InstanceMetadataService.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +/** @alpha */ +export type BackendFeatureMeta = + | { + type: 'plugin'; + pluginId: string; + } + | { + type: 'module'; + pluginId: string; + moduleId: string; + }; + +/** @alpha */ +export interface InstanceMetadataService { + getInstalledFeatures: () => BackendFeatureMeta[]; +} diff --git a/packages/backend-plugin-api/src/services/definitions/RootHttpRouterService.ts b/packages/backend-plugin-api/src/services/definitions/RootHttpRouterService.ts index a1006b749b..8bd0cad874 100644 --- a/packages/backend-plugin-api/src/services/definitions/RootHttpRouterService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootHttpRouterService.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Handler } from 'express'; +import type { Handler } from 'express'; /** * HTTP route registration for root services. diff --git a/packages/backend-plugin-api/src/services/definitions/RootLifecycleService.ts b/packages/backend-plugin-api/src/services/definitions/RootLifecycleService.ts index b962fa68ba..2fc9556938 100644 --- a/packages/backend-plugin-api/src/services/definitions/RootLifecycleService.ts +++ b/packages/backend-plugin-api/src/services/definitions/RootLifecycleService.ts @@ -23,4 +23,6 @@ import { LifecycleService } from './LifecycleService'; * * @public */ -export interface RootLifecycleService extends LifecycleService {} +export interface RootLifecycleService extends LifecycleService { + addBeforeShutdownHook(hook: () => void | Promise): void; +} diff --git a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts index a8b84b9084..24219228df 100644 --- a/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts +++ b/packages/backend-plugin-api/src/services/definitions/SchedulerService.ts @@ -354,19 +354,6 @@ export interface SchedulerService { getScheduledTasks(): Promise; } -function readDuration(config: Config, key: string): HumanDuration { - if (typeof config.get(key) === 'string') { - const value = config.getString(key); - const duration = Duration.fromISO(value); - if (!duration.isValid) { - throw new Error(`Invalid duration: ${value}`); - } - return duration.toObject(); - } - - return readDurationFromConfig(config, { key }); -} - function readFrequency( config: Config, key: string, @@ -382,7 +369,7 @@ function readFrequency( return { trigger: 'manual' }; } - return readDuration(config, key); + return readDurationFromConfig(config, { key }); } /** @@ -396,10 +383,10 @@ export function readSchedulerServiceTaskScheduleDefinitionFromConfig( config: Config, ): SchedulerServiceTaskScheduleDefinition { const frequency = readFrequency(config, 'frequency'); - const timeout = readDuration(config, 'timeout'); + const timeout = readDurationFromConfig(config, { key: 'timeout' }); const initialDelay = config.has('initialDelay') - ? readDuration(config, 'initialDelay') + ? readDurationFromConfig(config, { key: 'initialDelay' }) : undefined; const scope = config.getOptionalString('scope'); diff --git a/packages/backend-test-utils/CHANGELOG.md b/packages/backend-test-utils/CHANGELOG.md index b18ccbd3be..819d39a18d 100644 --- a/packages/backend-test-utils/CHANGELOG.md +++ b/packages/backend-test-utils/CHANGELOG.md @@ -1,5 +1,85 @@ # @backstage/backend-test-utils +## 1.2.0-next.2 + +### Patch Changes + +- 0e9c9fa: Mock the new `RootLifecycleService.addBeforeShutdownHook` method. +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-app-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 1.2.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/backend-app-api@1.1.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 1.2.0-next.0 + +### Minor Changes + +- de6f280: **BREAKING** Upgraded @keyv/redis and keyv packages to resolve a bug related to incorrect resolution of cache keys. + + This is a breaking change for clients using the `redis` store for cache with `useRedisSets` option set to false since cache keys will be calculated differently (without the sets:namespace: prefix). For clients with default configuration (or useRedisSets set to false) the cache keys will stay the same, but since @keyv/redis library no longer supports redis sets they won't be utilised anymore. + + If you were using `useRedisSets` option in configuration make sure to remove it from `app-config.yaml`: + + ```diff + backend: + cache: + store: redis + connection: redis://user:pass@cache.example.com:6379 + - useRedisSets: false + ``` + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-app-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 1.1.0 + +### Minor Changes + +- 5064827: Made it possible to construct `mockServices.database` with a given knex instance + +### Patch Changes + +- 7aae8e3: The `mockServices.discovery.factory()` factory now uses the mocked discovery service as its implementation, avoid the need for configuration. +- eb82994: Removed unused `msw` dependency. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-app-api@1.0.2 + - @backstage/errors@1.2.5 + ## 1.1.0-next.3 ### Patch Changes diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index a214a19525..ba23642a52 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.1.0-next.3", + "version": "1.2.0-next.2", "description": "Test helpers library for Backstage backends", "backstage": { "role": "node-library" @@ -53,8 +53,8 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-events-node": "workspace:^", "@backstage/types": "workspace:^", - "@keyv/memcache": "^1.3.5", - "@keyv/redis": "^2.5.3", + "@keyv/memcache": "^2.0.1", + "@keyv/redis": "^4.0.1", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", "@types/keyv": "^4.2.0", @@ -63,7 +63,7 @@ "cookie": "^0.7.0", "express": "^4.17.1", "fs-extra": "^11.0.0", - "keyv": "^4.5.2", + "keyv": "^5.2.1", "knex": "^3.0.0", "mysql2": "^3.0.0", "pg": "^8.11.3", diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts index a2c3b34ead..b9bca62767 100644 --- a/packages/backend-test-utils/src/next/services/mockServices.ts +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -472,6 +472,7 @@ export namespace mockServices { export const factory = () => rootLifecycleServiceFactory; export const mock = simpleMock(coreServices.rootLifecycle, () => ({ addShutdownHook: jest.fn(), + addBeforeShutdownHook: jest.fn(), addStartupHook: jest.fn(), })); } diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 96bf0f7dc1..42b46f4de7 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -251,7 +251,7 @@ export async function startTestBackend( const app = express(); const middleware = MiddlewareFactory.create({ config, logger }); - const healthRouter = createHealthRouter({ health }); + const healthRouter = createHealthRouter({ config, health }); app.use(healthRouter); app.use(router.handler()); diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 43eebd51e3..27c2a067b7 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -1,5 +1,157 @@ # example-backend +## 0.0.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-backend@1.28.0-next.2 + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.2 + - @backstage/plugin-notifications-backend@0.5.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-app-backend@0.4.3-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.2 + - @backstage/plugin-devtools-backend@0.5.0-next.2 + - @backstage/plugin-events-backend@0.4.0-next.2 + - @backstage/plugin-kubernetes-backend@0.19.1-next.2 + - @backstage/plugin-proxy-backend@0.5.9-next.2 + - @backstage/plugin-search-backend@1.8.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-signals-backend@0.2.4-next.2 + - @backstage/plugin-techdocs-backend@1.11.4-next.2 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.2 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.2 + - @backstage/plugin-permission-backend@0.5.52-next.2 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.2 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.0.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-events-backend@0.4.0-next.1 + - @backstage/plugin-search-backend@1.8.0-next.1 + - @backstage/plugin-devtools-backend@0.5.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.1 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.1 + - @backstage/plugin-notifications-backend@0.4.4-next.1 + - @backstage/plugin-permission-backend@0.5.52-next.1 + - @backstage/plugin-techdocs-backend@1.11.4-next.1 + - @backstage/plugin-signals-backend@0.2.4-next.1 + - @backstage/plugin-proxy-backend@0.5.9-next.1 + - @backstage/plugin-app-backend@0.4.3-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.1 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.1 + - @backstage/plugin-kubernetes-backend@0.19.1-next.1 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-scaffolder-backend@1.28.0-next.1 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.1 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.1 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.5-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-permission-common@0.8.2 + +## 0.0.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/plugin-scaffolder-backend@1.28.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-techdocs@0.3.4-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-search-backend-module-explore@0.2.6-next.0 + - @backstage/plugin-app-backend@0.4.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-backend@0.5.52-next.0 + - @backstage/plugin-devtools-backend@0.4.3-next.0 + - @backstage/plugin-signals-backend@0.2.4-next.0 + - @backstage/plugin-events-backend@0.3.17-next.0 + - @backstage/plugin-kubernetes-backend@0.19.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-auth-backend@0.24.1-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.3-next.0 + - @backstage/plugin-catalog-backend-module-openapi@0.2.5-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.3-next.0 + - @backstage/plugin-notifications-backend@0.4.4-next.0 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.3-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-proxy-backend@0.5.9-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.5.3-next.0 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.4-next.0 + - @backstage/plugin-search-backend@1.7.1-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-techdocs-backend@1.11.4-next.0 + +## 0.0.32 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-app-backend@0.4.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-scaffolder-backend@1.27.0 + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-search-backend@1.7.0 + - @backstage/plugin-events-backend@0.3.16 + - @backstage/plugin-kubernetes-backend@0.19.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-search-backend-module-explore@0.2.5 + - @backstage/plugin-catalog-backend-module-openapi@0.2.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-backend@0.4.3 + - @backstage/plugin-signals-backend@0.2.3 + - @backstage/plugin-catalog-backend-module-backstage-openapi@0.4.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-proxy-backend@0.5.8 + - @backstage/plugin-scaffolder-backend-module-notifications@0.1.3 + - @backstage/plugin-auth-backend-module-guest-provider@0.2.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-catalog-backend-module-unprocessed@0.5.2 + - @backstage/plugin-devtools-backend@0.4.2 + - @backstage/plugin-permission-backend@0.5.51 + - @backstage/plugin-permission-backend-module-allow-all-policy@0.2.2 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-github@0.5.2 + - @backstage/plugin-search-backend-module-techdocs@0.3.2 + - @backstage/plugin-techdocs-backend@1.11.2 + ## 0.0.32-next.3 ### Patch Changes diff --git a/packages/backend/package.json b/packages/backend/package.json index 255fc68a0e..0e8cf10fed 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "example-backend", - "version": "0.0.32-next.3", + "version": "0.0.33-next.2", "backstage": { "role": "backend" }, @@ -62,7 +62,7 @@ "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-signals-backend": "workspace:^", "@backstage/plugin-techdocs-backend": "workspace:^", - "@opentelemetry/auto-instrumentations-node": "^0.52.0", + "@opentelemetry/auto-instrumentations-node": "^0.54.0", "@opentelemetry/exporter-prometheus": "^0.54.0", "@opentelemetry/sdk-node": "^0.54.0", "example-app": "link:../app" diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index d8a4bcb98f..8ae9864a4a 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -59,5 +59,6 @@ backend.add(searchLoader); backend.add(import('@backstage/plugin-techdocs-backend')); backend.add(import('@backstage/plugin-signals-backend')); backend.add(import('@backstage/plugin-notifications-backend')); +backend.add(import('./instanceMetadata')); backend.start(); diff --git a/packages/backend/src/instanceMetadata.ts b/packages/backend/src/instanceMetadata.ts new file mode 100644 index 0000000000..5f835f3117 --- /dev/null +++ b/packages/backend/src/instanceMetadata.ts @@ -0,0 +1,40 @@ +/* + * 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 { + coreServices, + createBackendPlugin, +} from '@backstage/backend-plugin-api'; +import { instanceMetadataServiceRef } from '@backstage/backend-plugin-api/alpha'; + +// Example usage of the instance metadata service to log the installed features. +export default createBackendPlugin({ + pluginId: 'instance-metadata-logging', + register(env) { + env.registerInit({ + deps: { + instanceMetadata: instanceMetadataServiceRef, + logger: coreServices.logger, + }, + async init({ instanceMetadata, logger }) { + logger.info( + `Installed features on this instance: ${instanceMetadata + .getInstalledFeatures() + .join(', ')}`, + ); + }, + }); + }, +}); diff --git a/packages/canon/.eslintrc.js b/packages/canon/.eslintrc.js new file mode 100644 index 0000000000..f7c0e8cbd1 --- /dev/null +++ b/packages/canon/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + ...require('@backstage/cli/config/eslint-factory')(__dirname), + extends: ['plugin:storybook/recommended'], + rules: { + 'react/forbid-elements': 'off', + }, +}; + diff --git a/packages/canon/.gitignore b/packages/canon/.gitignore new file mode 100644 index 0000000000..86fa479d2f --- /dev/null +++ b/packages/canon/.gitignore @@ -0,0 +1,2 @@ +# Build output +storybook-static diff --git a/packages/canon/.storybook/main.ts b/packages/canon/.storybook/main.ts new file mode 100644 index 0000000000..41df32404b --- /dev/null +++ b/packages/canon/.storybook/main.ts @@ -0,0 +1,40 @@ +import type { StorybookConfig } from '@storybook/react-webpack5'; +import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin'; +import { merge } from 'webpack-merge'; + +import { join, dirname } from 'path'; + +/** + * This function is used to resolve the absolute path of a package. + * It is needed in projects that use Yarn PnP or are set up within a monorepo. + */ +function getAbsolutePath(value: string): any { + return dirname(require.resolve(join(value, 'package.json'))); +} +const config: StorybookConfig = { + stories: [ + '../docs/**/*.mdx', + '../src/components/**/*.mdx', + '../src/components/**/*.stories.@(js|jsx|mjs|ts|tsx)', + ], + staticDirs: ['../static'], + addons: [ + getAbsolutePath('@storybook/addon-webpack5-compiler-swc'), + getAbsolutePath('@storybook/addon-essentials'), + getAbsolutePath('@chromatic-com/storybook'), + getAbsolutePath('@storybook/addon-interactions'), + getAbsolutePath('@storybook/addon-themes'), + ], + framework: { + name: getAbsolutePath('@storybook/react-webpack5'), + options: { + plugins: [new VanillaExtractPlugin()], + }, + }, + webpackFinal: config => { + return merge(config, { + plugins: [new VanillaExtractPlugin()], + }); + }, +}; +export default config; diff --git a/packages/canon/.storybook/manager.ts b/packages/canon/.storybook/manager.ts new file mode 100644 index 0000000000..c88b10b392 --- /dev/null +++ b/packages/canon/.storybook/manager.ts @@ -0,0 +1,12 @@ +import { addons } from '@storybook/manager-api'; +import { create } from '@storybook/theming'; + +const theme = create({ + base: 'light', + brandTitle: 'Canon', + brandImage: 'logo.svg', +}); + +addons.setConfig({ + theme, +}); diff --git a/packages/canon/.storybook/preview.tsx b/packages/canon/.storybook/preview.tsx new file mode 100644 index 0000000000..db17d95afa --- /dev/null +++ b/packages/canon/.storybook/preview.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import type { Preview, ReactRenderer } from '@storybook/react'; +import { withThemeByDataAttribute } from '@storybook/addon-themes'; + +// Storybook specific styles +import '../docs/components/styles.css'; + +// Canon specific styles +import '../src/css/core.css'; +import '../src/css/components.css'; + +// Custom themes +import './themes/backstage.css'; +import { ThemeProvider } from '../src/theme/context'; + +const preview: Preview = { + parameters: { + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/i, + }, + }, + backgrounds: { + disable: true, + }, + options: { + storySort: { + method: 'alphabetical', + order: ['Core Concepts', 'Components'], + }, + }, + viewport: { + viewports: { + small: { + name: 'Small', + styles: { + width: '640px', + height: '100%', + }, + }, + medium: { + name: 'Medium', + styles: { + width: '768px', + height: '100%', + }, + }, + large: { + name: 'Large', + styles: { + width: '1024px', + height: '100%', + }, + }, + xlarge: { + name: 'XLarge', + styles: { + width: '1280px', + height: '100%', + }, + }, + '2xl': { + name: '2XL', + styles: { + width: '1536px', + height: '100%', + }, + }, + }, + defaultViewport: 'small', + }, + }, + decorators: [ + withThemeByDataAttribute({ + themes: { + Light: 'light', + Dark: 'dark', + 'Backstage Light': 'backstage-light', + 'Backstage Dark': 'backstage-dark', + }, + defaultTheme: 'Light', + }), + Story => { + document.body.style.backgroundColor = 'var(--canon-background)'; + + const docsStoryElements = document.getElementsByClassName('docs-story'); + Array.from(docsStoryElements).forEach(element => { + (element as HTMLElement).style.backgroundColor = + 'var(--canon-background)'; + }); + + return ( + + + + ); + }, + ], +}; + +export default preview; diff --git a/packages/canon/.storybook/themes/backstage.css b/packages/canon/.storybook/themes/backstage.css new file mode 100644 index 0000000000..4a7821cda2 --- /dev/null +++ b/packages/canon/.storybook/themes/backstage.css @@ -0,0 +1,75 @@ +[data-theme='backstage-light'] { + /* Colors */ + --canon-accent: #2e77d0; + --canon-background: #f8f8f8; + --canon-surface-1: #fff; + --canon-surface-2: #f4f4f4; + + /* Text colors */ + --canon-text-primary: #000; + --canon-text-primary-on-accent: #fff; + --canon-text-secondary: #646464; + + --canon-font-regular: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; + + .button { + border-radius: 60px; + font-weight: 400; + text-transform: uppercase; + font-size: 0.875rem; + transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, + box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, + border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; + line-height: 1.75; + border-radius: 4px; + background-color: #1f5493; + padding: 6px 16px; + box-shadow: none; + } + + .button:hover { + box-shadow: none; + } + + .button.primary { + color: #fff; + background-color: rgb(21, 58, 102); + box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), + 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12); + } + + .button.primary:hover { + box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), + 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12); + } + + .button.secondary { + background-color: transparent; + border: 1px solid rgba(31, 84, 147, 0.5); + color: #1f5493; + } + + .button.secondary:hover { + border: 1px solid #1f5493; + background-color: rgba(31, 84, 147, 0.04); + } + + .button.tertiary { + background-color: transparent; + border: none; + color: #1f5493; + } +} + +[data-theme='backstage-dark'] { + /* Colors */ + --canon-accent: #2e77d0; + --canon-background: #000; + --canon-surface-1: #121212; + --canon-surface-2: #1a1a1a; + + /* Text colors */ + --canon-text-primary: #fff; + --canon-text-primary-on-accent: #000; + --canon-text-secondary: #b3b3b3; +} diff --git a/packages/canon/README.md b/packages/canon/README.md new file mode 100644 index 0000000000..a8bf36d7be --- /dev/null +++ b/packages/canon/README.md @@ -0,0 +1,12 @@ +# @backstage/canon + +_This package was created through the Backstage CLI_. + +## Installation + +Install the package via Yarn: + +```sh +cd # if within a monorepo +yarn add @backstage/canon +``` diff --git a/packages/canon/catalog-info.yaml b/packages/canon/catalog-info.yaml new file mode 100644 index 0000000000..8369c314b3 --- /dev/null +++ b/packages/canon/catalog-info.yaml @@ -0,0 +1,9 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: backstage-canon + title: '@backstage/canon' +spec: + lifecycle: experimental + type: backstage-web-library + owner: design-system-maintainers diff --git a/packages/canon/docs/Home.mdx b/packages/canon/docs/Home.mdx new file mode 100644 index 0000000000..5b85ab15ad --- /dev/null +++ b/packages/canon/docs/Home.mdx @@ -0,0 +1,91 @@ +import { Unstyled } from '@storybook/blocks'; +import { + Columns, + Text, + ComponentStatus, + Banner, + Title, + Roadmap, +} from './components'; +import { list } from './components/Roadmap/list'; + + + + + + + Welcome to the Canon, the new design library for Backstage plugins. This + project is still under active development but we will make sure to document + the API as we go. We are aiming to improve the general UI of Backstage and + plugins across Backstage. This new library will take time to build but we are + building it incrementally with not conflict with the existing theming system. + + + + This library is still under heavy construction. Please be aware that the API + will change until we reach a stable release. + + + + Component Status + + + We are still in the process of documenting the API and building the + components. You can use the statuses below to see what is ready and what is + coming soon. If there is a component missing that you need, please let us know + by opening an issue on GitHub. + + + + + + + + + + + + + + + + + + + + + + Roadmap + + + + + diff --git a/packages/canon/docs/Iconography.mdx b/packages/canon/docs/Iconography.mdx new file mode 100644 index 0000000000..83d181af12 --- /dev/null +++ b/packages/canon/docs/Iconography.mdx @@ -0,0 +1,22 @@ +import { Unstyled, Source, Meta } from '@storybook/blocks'; +import { Title, Text, IconLibrary } from './components'; + + + + + +Iconography + + + All our default icons are provided by [Remix Icon](https://remixicon.com/). We + don't import all icons to reduce the bundle size but we cherry pick a nice + selection for you to use in your application. The list of names is set down + below. To use an icon, you can use the `Icon` component and pass the name of + the icon you want to use. + + +`} language="tsx" dark /> + + + + diff --git a/packages/canon/docs/Layout.mdx b/packages/canon/docs/Layout.mdx new file mode 100644 index 0000000000..9145f71aed --- /dev/null +++ b/packages/canon/docs/Layout.mdx @@ -0,0 +1,54 @@ +import { Unstyled, Source, Meta } from '@storybook/blocks'; +import { Title, Text, LayoutComponents } from './components'; +import * as Table from './components/Table'; + + + + + +Layout + + Canon is made for extensibility. We built this library to make it easy for any + Backstage plugin creator to be able to build their ideas at speed ensuring + consistency across the rest of your ecosystem. Each component is designed to + be editable to match your need but sometimes you want to have more control + over the layout of your page. To help you with that, we created a set of + layout components that you can use to build your own layouts. All of these + components are built to extend on our theming system, making it easy for you + to build your own layouts. Sometimes these components are not enough so we + created a set of helpers to be used with any CSS-in-JS library. + + +Layout Components + + + We built a couple of layout components to help you build responsive elements + that will be consistent with the rest of your Backstage instance. These + components are opinionated and use TypeScript to ensure that the props you + provide are the ones coming from the theme. + + + + Hello World + + Project 1 + Project 2 + +`} + language="tsx" + dark +/> + + + +Layout Helpers + + + Sometimes you want to use global tokens dynamically outside of React + components. To help you with that we would like to provide a set of helpers + that you can use in your code. These helpers are not available just yet but we + are working on it. + + + diff --git a/packages/canon/docs/Theme.mdx b/packages/canon/docs/Theme.mdx new file mode 100644 index 0000000000..1ea7c5c4c6 --- /dev/null +++ b/packages/canon/docs/Theme.mdx @@ -0,0 +1,231 @@ +import { Unstyled, Source, Meta } from '@storybook/blocks'; +import { Title, Text, Chip } from './components'; +import * as Table from './components/Table'; + +{' '} + + + +Theming + + Backstage ships with a default theme with a light and dark mode variant. The + themes are provided as a part of the `@backstage/canon` package, which also + includes utilities for customizing the default theme, or creating completely + new themes. + + +Light & Dark modes + + By default we are supporting both light and dark modes. Each user can opt to + choose what theme they want to use or to use their system decide what theme to + use. If you want to create your own theme, you will have to set both light and + dark themes following the instructions below. If you only set one of them, the + other mode will fallback to the default theme. + + +How to create your own theme + + To create your own theme, you will have to define the variables below. To do + that, create a theme.css file and import it in your application. Here's an + example below on how to set your light and dark mode. + + + +Colors + + We provide a set of generic colours tokens that we use across Canon. By + changing these colours you can easily change the look and feel of your + application to match your brand. + + + + + Prop + Description + + + + + + --canon-accent + + The accent color for the theme. + + + + --canon-bg + + The background color for the theme. + + + + --canon-surface-1 + + The first surface color for the theme. + + + + --canon-surface-2 + + The second surface color for the theme. + + + + --canon-outline + + The outline color for the theme. + + + + --canon-outline-focus + + The outline focus color for the theme. + + + + --canon-text-primary + + The primary text color for the theme. + + + + --canon-text-secondary + + The secondary text color for the theme. + + + + +Typography + + We have two fonts that we use across Canon. The first one is the sans-serif + font that we use for the body of the application. The second one is the + monospace font that we use for code blocks and tables. + + + + + + Prop + Description + + + + + + --canon-font-regular + + The sans-serif font for the theme. + + + + --canon-font-mono + + The monospace font for the theme. + + + + +Spacing + + Our default spacing system is made to work in most scenarios. We have 7 scale + values from `xxs` to `xxl`. We use the values on padding and margin in our + layout components mostly. If you prefer to use a different spacing system, you + can do that by changing the values below. + + + + + + Prop + Description + + + + + + --canon-space-unit + + + The base unit for the spacing system. Default value is `1em` + + + + + --canon-space-xxs + + Default value is `0.25 x space unit` + + + + --canon-space-xs + + Default value is `0.5 x space unit` + + + + --canon-space-sm + + Default value is `0.75 x space unit` + + + + --canon-space-md + + Default value is `1.25 x space unit` + + + + --canon-space-lg + + Default value is `2 x space unit` + + + + --canon-space-xl + + Default value is `3.25 x space unit` + + + + --canon-space-xxl + + Default value is `5.25 x space unit` + + + + + diff --git a/packages/canon/docs/Typography.mdx b/packages/canon/docs/Typography.mdx new file mode 100644 index 0000000000..802b9881be --- /dev/null +++ b/packages/canon/docs/Typography.mdx @@ -0,0 +1,48 @@ +import { Unstyled, Meta, Canvas } from '@storybook/blocks'; +import { + Columns, + Text, + ComponentStatus, + Banner, + Title, + Roadmap, +} from './components'; +import { list } from './components/Roadmap/list'; +import * as HeadingStories from '../src/components/Heading/Heading.stories'; +import * as TextStories from '../src/components/Text/Text.stories'; + + + + + +Typography + + Canon offers a suite of typography components designed to seamlessly align + with the rest of your Backstage instance. While you can customize their + appearance to match your brand, the underlying API remains consistent and + unchanged. Each component is built on a responsive structure, allowing you to + define different typography values for various breakpoints. + + +Heading + + Headings are used to structure the content of your page. They are used to + create a hierarchy of information and to make the content more readable. The + best way to use add these headings to your page is to import the [Heading + component](?path=/docs/components-heading--docs). + + + + +Text + + Canon provides four distinct text variants, each offering different font sizes + carefully designed to cover the majority of use cases. These variants are + versatile and can be paired with regular and bold of font weights. You can use + the [Text component](?path=/docs/components-text--docs) to add text to your + page. + + + + + diff --git a/packages/canon/docs/components/Banner/Banner.tsx b/packages/canon/docs/components/Banner/Banner.tsx new file mode 100644 index 0000000000..3199e65bc0 --- /dev/null +++ b/packages/canon/docs/components/Banner/Banner.tsx @@ -0,0 +1,41 @@ +/* + * 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 React from 'react'; + +export const Banner = ({ + children, + variant = 'info', +}: { + children: React.ReactNode; + variant?: 'info' | 'warning'; +}) => { + return ( +
+
+ + + +
+ {children} +
+ ); +}; diff --git a/packages/canon/docs/components/Banner/index.ts b/packages/canon/docs/components/Banner/index.ts new file mode 100644 index 0000000000..31f4aa88b0 --- /dev/null +++ b/packages/canon/docs/components/Banner/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Banner } from './Banner'; diff --git a/packages/canon/docs/components/Banner/styles.css b/packages/canon/docs/components/Banner/styles.css new file mode 100644 index 0000000000..6fec3345ae --- /dev/null +++ b/packages/canon/docs/components/Banner/styles.css @@ -0,0 +1,38 @@ +.banner { + display: flex; + align-items: center; + font-family: 'Geist', sans-serif; + font-size: 16px; + line-height: 28px; + padding: 16px; + border-radius: 6px; + margin-bottom: 16px; + border: 1px solid #e0e0e0; + + & > p { + margin: 0; + } + + &.info { + background-color: #f2f2f2; + border-color: #cdcdcd; + color: #888888; + } + + &.warning { + background-color: #fff2b9; + border-color: #ffd000; + color: #d79927; + } + + & .icon { + width: 32px; + height: 32px; + background-color: rgba(215, 153, 39, 0.2); + border-radius: 6px; + margin-right: 16px; + display: flex; + align-items: center; + justify-content: center; + } +} diff --git a/packages/canon/docs/components/Chip/Chip.tsx b/packages/canon/docs/components/Chip/Chip.tsx new file mode 100644 index 0000000000..e6e1d1b1c4 --- /dev/null +++ b/packages/canon/docs/components/Chip/Chip.tsx @@ -0,0 +1,27 @@ +/* + * 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 React from 'react'; + +export const Chip = ({ + children, + head = false, +}: { + children: React.ReactNode; + head?: boolean; +}) => { + return {children}; +}; diff --git a/packages/canon/docs/components/Chip/index.ts b/packages/canon/docs/components/Chip/index.ts new file mode 100644 index 0000000000..ff9e4794c5 --- /dev/null +++ b/packages/canon/docs/components/Chip/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Chip } from './Chip'; diff --git a/packages/canon/docs/components/Chip/styles.css b/packages/canon/docs/components/Chip/styles.css new file mode 100644 index 0000000000..95cf7cef34 --- /dev/null +++ b/packages/canon/docs/components/Chip/styles.css @@ -0,0 +1,33 @@ +/* + * 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. + */ + +.chip { + display: inline-flex; + align-items: center; + font-family: monospace; + font-size: 13px; + border-radius: 6px; + padding: 0px 8px; + height: 24px; + margin-right: 4px; + background-color: #f0f0f0; + color: #5d5d5d; + + &.head { + background-color: #eaf2fd; + color: #2563eb; + } +} diff --git a/plugins/config-schema/src/components/SchemaView/ScalarView.tsx b/packages/canon/docs/components/Columns/Columns.tsx similarity index 55% rename from plugins/config-schema/src/components/SchemaView/ScalarView.tsx rename to packages/canon/docs/components/Columns/Columns.tsx index aeea1c04d7..115ec50010 100644 --- a/plugins/config-schema/src/components/SchemaView/ScalarView.tsx +++ b/packages/canon/docs/components/Columns/Columns.tsx @@ -1,5 +1,5 @@ /* - * Copyright 2021 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,21 +14,18 @@ * limitations under the License. */ -import Box from '@material-ui/core/Box'; -import Typography from '@material-ui/core/Typography'; import React from 'react'; -import { MetadataView } from './MetadataView'; -import { SchemaViewProps } from './types'; -export function ScalarView({ schema }: SchemaViewProps) { +export const Columns = ({ + children, + style, +}: { + children: React.ReactNode; + style?: React.CSSProperties; +}) => { return ( - <> - {schema.description && ( - - {schema.description} - - )} - - +
+ {children} +
); -} +}; diff --git a/packages/canon/docs/components/Columns/index.ts b/packages/canon/docs/components/Columns/index.ts new file mode 100644 index 0000000000..05de0850be --- /dev/null +++ b/packages/canon/docs/components/Columns/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Columns } from './Columns'; diff --git a/packages/canon/docs/components/Columns/styles.css b/packages/canon/docs/components/Columns/styles.css new file mode 100644 index 0000000000..c34acfc406 --- /dev/null +++ b/packages/canon/docs/components/Columns/styles.css @@ -0,0 +1,22 @@ +/* + * 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. + */ + +.columns { + display: grid; + grid-template-columns: repeat(3, 1fr); + row-gap: 20px; + column-gap: 80px; +} diff --git a/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx b/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx new file mode 100644 index 0000000000..0159e27b32 --- /dev/null +++ b/packages/canon/docs/components/ComponentStatus/ComponentStatus.tsx @@ -0,0 +1,48 @@ +/* + * 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 React from 'react'; + +export const ComponentStatus = ({ + name, + status = 'notStarted', + style, + link, +}: { + name: string; + status: 'notStarted' | 'inProgress' | 'alpha' | 'beta' | 'stable'; + style?: React.CSSProperties; + link?: string; +}) => { + return ( +
+ {link ? ( + + {name} + + ) : ( + {name} + )} + + {status === 'notStarted' && 'Not Started'} + {status === 'inProgress' && 'In Progress'} + {status === 'alpha' && 'Alpha'} + {status === 'beta' && 'Beta'} + {status === 'stable' && 'Stable'} + +
+ ); +}; diff --git a/packages/canon/docs/components/ComponentStatus/index.ts b/packages/canon/docs/components/ComponentStatus/index.ts new file mode 100644 index 0000000000..238c001289 --- /dev/null +++ b/packages/canon/docs/components/ComponentStatus/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { ComponentStatus } from './ComponentStatus'; diff --git a/packages/canon/docs/components/ComponentStatus/styles.css b/packages/canon/docs/components/ComponentStatus/styles.css new file mode 100644 index 0000000000..f800e659e0 --- /dev/null +++ b/packages/canon/docs/components/ComponentStatus/styles.css @@ -0,0 +1,73 @@ +/* + * 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. + */ + +.component-status { + display: flex; + justify-content: space-between; + + & .title { + color: #3b59ff; + font-family: 'Geist', sans-serif; + font-size: 16px; + font-weight: 400; + text-decoration: none; + } + + & .pill { + font-family: 'Geist', sans-serif; + display: inline-flex; + align-items: center; + color: #000; + border-radius: 40px; + padding: 0px 8px; + height: 24px; + font-size: 12px; + font-weight: 600; + border-style: solid; + border-width: 1px; + margin-left: 8px; + + &.notStarted { + background-color: #f2f2f2; + border-color: #cdcdcd; + color: #888888; + } + + &.inProgress { + background-color: #fff2b9; + border-color: #ffd000; + color: #d79927; + } + + &.alpha { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; + } + + &.beta { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; + } + + &.stable { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; + } + } +} diff --git a/packages/canon/docs/components/IconLibrary/IconLibrary.tsx b/packages/canon/docs/components/IconLibrary/IconLibrary.tsx new file mode 100644 index 0000000000..e32f4c08a4 --- /dev/null +++ b/packages/canon/docs/components/IconLibrary/IconLibrary.tsx @@ -0,0 +1,37 @@ +/* + * 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 React from 'react'; +import { Icon } from '@backstage/canon'; +import type { IconNames } from '@backstage/canon'; +import { defaultIcons } from '../../../src/components/Icon/icons'; +import { Text } from '../Text/Text'; + +export const IconLibrary = () => { + const icons = Object.keys(defaultIcons); + + return ( +
+ {icons.map(icon => ( +
+
+ +
+ {icon} +
+ ))} +
+ ); +}; diff --git a/packages/canon/docs/components/IconLibrary/index.ts b/packages/canon/docs/components/IconLibrary/index.ts new file mode 100644 index 0000000000..071c80db85 --- /dev/null +++ b/packages/canon/docs/components/IconLibrary/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { IconLibrary } from './IconLibrary'; diff --git a/packages/canon/docs/components/IconLibrary/styles.css b/packages/canon/docs/components/IconLibrary/styles.css new file mode 100644 index 0000000000..1a6f63ca79 --- /dev/null +++ b/packages/canon/docs/components/IconLibrary/styles.css @@ -0,0 +1,22 @@ +.icon-library { + display: grid; + grid-template-columns: repeat(6, 1fr); + gap: 1rem; +} + +.icon-library-item { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; +} + +.icon-library-item-icon { + display: flex; + width: 100%; + justify-content: center; + align-items: center; + height: 80px; + border: 1px solid #d3d3d3; + border-radius: 0.5rem; +} diff --git a/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx b/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx new file mode 100644 index 0000000000..56f389a389 --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/LayoutComponents.tsx @@ -0,0 +1,64 @@ +/* + * 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 React from 'react'; +import { BoxSvg } from './svgs/box'; +import { StackSvg } from './svgs/stack'; +import { GridSvg } from './svgs/grid'; +import { InlineSvg } from './svgs/inline'; +import { ContainerSvg } from './svgs/container'; + +export const LayoutComponents = () => { + return ( +
+
+ + + +
Box
+
The most basic layout component
+
+
+ + + +
Stack
+
Arrange your components vertically
+
+
+ + + +
Grid
+
Arrange your components in a grid
+
+
+ + + +
Inline
+
Arrange your components in a row
+
+
+ + + +
Container
+
A container for your components
+
+
+ ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/index.ts b/packages/canon/docs/components/LayoutComponents/index.ts new file mode 100644 index 0000000000..55cc9f25ef --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { LayoutComponents } from './LayoutComponents'; diff --git a/packages/canon/docs/components/LayoutComponents/styles.css b/packages/canon/docs/components/LayoutComponents/styles.css new file mode 100644 index 0000000000..c2a819cf6b --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/styles.css @@ -0,0 +1,60 @@ +/* + * 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. + */ + +.layout-components { + display: flex; + justify-content: flex-start; + gap: 1rem; + flex-wrap: wrap; + + & .box { + display: flex; + flex-direction: column; + width: calc(33.33% - 0.67rem); + margin-bottom: 1rem; + align-items: flex-start; + } + + & .content { + flex: none; + background: linear-gradient(180deg, #f3f3f3 0%, #fff 100%); + border-radius: 4px; + width: 100%; + height: 180px; + transition: all 0.2s ease-in-out; + margin-bottom: 0.75rem; + display: flex; + align-items: center; + justify-content: center; + + &:hover { + transform: translateY(-4px); + } + } + + & .title { + font-size: 16px; + font-family: 'Geist', sans-serif; + transition: color 0.2s ease-in-out; + margin-bottom: 0.25rem; + } + + & .description { + font-size: 16px; + font-family: 'Geist', sans-serif; + color: #9e9e9e; + } +} diff --git a/packages/canon/docs/components/LayoutComponents/svgs/box.tsx b/packages/canon/docs/components/LayoutComponents/svgs/box.tsx new file mode 100644 index 0000000000..1749b38c6f --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/svgs/box.tsx @@ -0,0 +1,54 @@ +/* + * 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 React from 'react'; + +export const BoxSvg = () => { + return ( + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/svgs/container.tsx b/packages/canon/docs/components/LayoutComponents/svgs/container.tsx new file mode 100644 index 0000000000..62fe4ce266 --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/svgs/container.tsx @@ -0,0 +1,373 @@ +/* + * 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 React from 'react'; + +export const ContainerSvg = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx b/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx new file mode 100644 index 0000000000..5527d1f3e2 --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/svgs/grid.tsx @@ -0,0 +1,91 @@ +/* + * 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 React from 'react'; + +export const GridSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx b/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx new file mode 100644 index 0000000000..fadb9bfc1b --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/svgs/inline.tsx @@ -0,0 +1,92 @@ +/* + * 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 React from 'react'; + +export const InlineSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx b/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx new file mode 100644 index 0000000000..aeda998d2e --- /dev/null +++ b/packages/canon/docs/components/LayoutComponents/svgs/stack.tsx @@ -0,0 +1,82 @@ +/* + * 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 React from 'react'; + +export const StackSvg = () => { + return ( + + + + + + + + + + + + ); +}; diff --git a/packages/canon/docs/components/PropsTable/PropsTable.tsx b/packages/canon/docs/components/PropsTable/PropsTable.tsx new file mode 100644 index 0000000000..a3dc9e271c --- /dev/null +++ b/packages/canon/docs/components/PropsTable/PropsTable.tsx @@ -0,0 +1,57 @@ +/* + * 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 React from 'react'; +import * as Table from '..'; +import { Chip } from '..'; + +// Modify the PropsTable component to accept a generic type +export const PropsTable = >({ + data, +}: { + data: T; +}) => { + return ( + + + + Prop + Type + Responsive + + + + {Object.keys(data).map(n => ( + + + {n} + + + {Array.isArray(data[n].type) ? ( + data[n].type.map((t: any) => {t}) + ) : ( + {data[n].type} + )} + + + {data[n].responsive ? 'Yes' : 'No'} + + + ))} + + + ); +}; diff --git a/packages/canon/docs/components/PropsTable/getProps.ts b/packages/canon/docs/components/PropsTable/getProps.ts new file mode 100644 index 0000000000..5773eaeb27 --- /dev/null +++ b/packages/canon/docs/components/PropsTable/getProps.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ +export function getProps(styles: Record) { + return Object.keys(styles).reduce( + (acc: Record, n) => { + const style = styles[n]; + + let values: string[] = []; + + if (style.values) { + // If values exist, use them + values = Object.keys(style.values); + } else if (style.mappings && style.mappings.length > 0) { + // If mappings exist, use the first mapping's values + const firstMapping = style.mappings[0]; + values = Object.keys(styles[firstMapping].values); + } else { + // Default to an empty array if neither values nor mappings exist + values = []; + } + + acc[n] = { + type: values, + responsive: true, + }; + return acc; + }, + {} as Record, + ); +} diff --git a/packages/canon/docs/components/PropsTable/index.ts b/packages/canon/docs/components/PropsTable/index.ts new file mode 100644 index 0000000000..181933f0f8 --- /dev/null +++ b/packages/canon/docs/components/PropsTable/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { PropsTable } from './PropsTable'; +export { getProps } from './getProps'; diff --git a/packages/canon/docs/components/Roadmap/Roadmap.tsx b/packages/canon/docs/components/Roadmap/Roadmap.tsx new file mode 100644 index 0000000000..2177ea558f --- /dev/null +++ b/packages/canon/docs/components/Roadmap/Roadmap.tsx @@ -0,0 +1,53 @@ +/* + * 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 React from 'react'; +import { RoadmapItem } from './list'; + +export const Roadmap = ({ list }: { list: RoadmapItem[] }) => { + const orderList = ['inProgress', 'notStarted', 'completed']; + return ( +
+ {list + .sort( + (a, b) => orderList.indexOf(a.status) - orderList.indexOf(b.status), + ) + .map(Item)} +
+ ); +}; + +const Item = ({ + title, + status = 'notStarted', +}: { + title: string; + status: 'notStarted' | 'inProgress' | 'inReview' | 'completed'; +}) => { + return ( +
+
+
+
{title}
+
+ + {status === 'notStarted' && 'Not Started'} + {status === 'inProgress' && 'In Progress'} + {status === 'inReview' && 'Ready for Review'} + {status === 'completed' && 'Completed'} + +
+ ); +}; diff --git a/packages/canon/docs/components/Roadmap/index.ts b/packages/canon/docs/components/Roadmap/index.ts new file mode 100644 index 0000000000..ac51dfa1ed --- /dev/null +++ b/packages/canon/docs/components/Roadmap/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Roadmap } from './Roadmap'; diff --git a/packages/canon/docs/components/Roadmap/list.ts b/packages/canon/docs/components/Roadmap/list.ts new file mode 100644 index 0000000000..d5f436281a --- /dev/null +++ b/packages/canon/docs/components/Roadmap/list.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ +export type RoadmapItem = { + title: string; + status: 'notStarted' | 'inProgress' | 'inReview' | 'completed'; +}; + +export const list: RoadmapItem[] = [ + { + title: 'Remove Vanilla Extract and use pure CSS instead', + status: 'inProgress', + }, + { + title: 'Add collapsing across breakpoints for the Inline component', + status: 'notStarted', + }, + { + title: 'Add reversing the order for the Inline component', + status: 'notStarted', + }, + { + title: 'Set up Storybook', + status: 'completed', + }, + { + title: 'Set up iconography', + status: 'completed', + }, + { + title: 'Set up global tokens', + status: 'inProgress', + }, + { + title: 'Set up theming system', + status: 'inProgress', + }, + { + title: 'Create first pass at box component', + status: 'completed', + }, + { + title: 'Create first pass at stack component', + status: 'completed', + }, + { + title: 'Create first pass at inline component', + status: 'completed', + }, +]; diff --git a/packages/canon/docs/components/Roadmap/styles.css b/packages/canon/docs/components/Roadmap/styles.css new file mode 100644 index 0000000000..e47aecf7fa --- /dev/null +++ b/packages/canon/docs/components/Roadmap/styles.css @@ -0,0 +1,102 @@ +.roadmap { + display: flex; + flex-direction: column; +} + +.roadmap .roadmap-item { + font-family: 'Geist', sans-serif; + display: flex; + align-items: center; + justify-content: space-between; + border-bottom: 1px solid #e0e0e0; + padding: 8px 0px; +} + +.roadmap .roadmap-item .left { + display: flex; + align-items: center; + padding-left: 12px; + gap: 12px; +} + +.roadmap .roadmap-item .dot { + width: 8px; + height: 8px; + border-radius: 50%; + background-color: #e0e0e0; +} + +.roadmap .roadmap-item.notStarted { + color: #000; +} + +.roadmap .roadmap-item.inProgress { + color: #000; +} + +.roadmap .roadmap-item.inReview { + color: #000; +} + +.roadmap .roadmap-item.completed .title { + color: #a2a2a2; + text-decoration: line-through; +} + +.roadmap .roadmap-item.notStarted .dot { + background-color: #d1d1d1; +} + +.roadmap .roadmap-item.inProgress .dot { + background-color: #ffd000; +} + +.roadmap .roadmap-item.inReview .dot { + background-color: #4ed14a; +} + +.roadmap .roadmap-item.completed .dot { + background-color: #4ed14a; +} + +.roadmap .roadmap-item .title { + font-weight: 300; + font-size: 16px; +} + +.roadmap .roadmap-item .pill { + display: inline-flex; + align-items: center; + height: 24px; + padding: 0px 8px; + border-radius: 40px; + font-size: 12px; + font-weight: 600; + margin-left: 8px; + border-style: solid; + border-width: 1px; +} + +.roadmap .roadmap-item.notStarted .pill { + background-color: #f2f2f2; + border-color: #cdcdcd; + color: #888888; +} + +.roadmap .roadmap-item.inProgress .pill { + background-color: #fff2b9; + border-color: #ffd000; + color: #d79927; +} + +.roadmap .roadmap-item.inReview .pill { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; +} + +.roadmap .roadmap-item.completed .pill { + background-color: #d7f9d7; + border-color: #4ed14a; + color: #3a9837; +} diff --git a/packages/canon/docs/components/Table/Table.tsx b/packages/canon/docs/components/Table/Table.tsx new file mode 100644 index 0000000000..74a26a89af --- /dev/null +++ b/packages/canon/docs/components/Table/Table.tsx @@ -0,0 +1,49 @@ +/* + * 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 React from 'react'; + +export const Root = ({ children }: { children: React.ReactNode }) => { + return ( +
+ {children}
+
+ ); +}; + +export const Header = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; + +export const Body = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; + +export const HeaderRow = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; + +export const HeaderCell = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; + +export const Row = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; + +export const Cell = ({ children }: { children: React.ReactNode }) => { + return {children}; +}; diff --git a/packages/canon/docs/components/Table/index.ts b/packages/canon/docs/components/Table/index.ts new file mode 100644 index 0000000000..7419aa83a8 --- /dev/null +++ b/packages/canon/docs/components/Table/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Root, Header, Body, Row, Cell, HeaderRow, HeaderCell } from './Table'; diff --git a/packages/canon/docs/components/Table/styles.css b/packages/canon/docs/components/Table/styles.css new file mode 100644 index 0000000000..fb9faf17eb --- /dev/null +++ b/packages/canon/docs/components/Table/styles.css @@ -0,0 +1,76 @@ +/* + * 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. + */ + +.sb-table-wrapper { + border: 1px solid #e7e7e7; + border-radius: 4px; + overflow: hidden; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + + & .sb-table { + width: 100%; + margin: 0 !important; + padding: 0 !important; + border-spacing: 0px; + border-collapse: collapse; + } + + & .sb-table-cell { + padding: 12px 16px !important; + border: none !important; + text-align: left; + background-color: white !important; + font-family: 'Geist', sans-serif; + font-size: 16px; + font-weight: 300; + + & p { + margin: 0; + } + } + + & .sb-table-header-cell { + background-color: #f5f5f5 !important; + border-bottom: 1px solid #e7e7e7 !important; + font-weight: 500; + font-size: 14px; + } + + & .sb-table-row { + border: none; + border-bottom: 1px solid #e7e7e7; + &:last-child { + border-bottom: none; + } + } + + & .sb-table-chip { + display: inline-block; + font-size: 14px !important; + border: 1px solid #e7e7e7; + border-radius: 6px; + padding: 0px 6px; + height: 24px; + } + + & .sb-table-type { + display: flex; + flex-wrap: wrap; + flex-direction: row; + gap: 8px; + } +} diff --git a/packages/canon/docs/components/Text/Text.tsx b/packages/canon/docs/components/Text/Text.tsx new file mode 100644 index 0000000000..90804b7da7 --- /dev/null +++ b/packages/canon/docs/components/Text/Text.tsx @@ -0,0 +1,31 @@ +/* + * 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 React from 'react'; + +export const Text = ({ + children, + style, +}: { + children: React.ReactNode; + style?: React.CSSProperties; +}) => { + return ( +
+ {children} +
+ ); +}; diff --git a/packages/canon/docs/components/Text/index.ts b/packages/canon/docs/components/Text/index.ts new file mode 100644 index 0000000000..873fca2c76 --- /dev/null +++ b/packages/canon/docs/components/Text/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Text } from './Text'; diff --git a/packages/canon/docs/components/Text/styles.css b/packages/canon/docs/components/Text/styles.css new file mode 100644 index 0000000000..7255ea802b --- /dev/null +++ b/packages/canon/docs/components/Text/styles.css @@ -0,0 +1,49 @@ +/* + * 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. + */ + +.sb-text { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + font-size: 16px; + line-height: 28px; + margin: 0; + font-weight: 300; + margin-bottom: 16px; + + & p { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; + font-size: 16px; + line-height: 28px; + margin: 0; + font-weight: 300; + } + + & code { + font-size: 13px; + color: #215cff; + background-color: #f1f3fc; + padding: 4px 4px; + border-radius: 4px; + } + + & a { + color: #215cff; + text-decoration: none; + border-bottom: 1px solid #215cff; + } +} diff --git a/packages/canon/docs/components/Title/Title.tsx b/packages/canon/docs/components/Title/Title.tsx new file mode 100644 index 0000000000..59fefad8f9 --- /dev/null +++ b/packages/canon/docs/components/Title/Title.tsx @@ -0,0 +1,38 @@ +/* + * 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 React from 'react'; + +export const Title = ({ + children, + style, + type = 'h1', +}: { + children: React.ReactNode; + style?: React.CSSProperties; + type?: 'h1' | 'h2' | 'h3'; +}) => { + let Component = 'h1'; + if (type === 'h1') Component = 'h1'; + if (type === 'h2') Component = 'h2'; + if (type === 'h3') Component = 'h3'; + + return React.createElement(Component, { + className: `sb-title ${type}`, + style, + children, + }); +}; diff --git a/packages/canon/docs/components/Title/index.ts b/packages/canon/docs/components/Title/index.ts new file mode 100644 index 0000000000..998dc81882 --- /dev/null +++ b/packages/canon/docs/components/Title/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export { Title } from './Title'; diff --git a/packages/canon/docs/components/Title/styles.css b/packages/canon/docs/components/Title/styles.css new file mode 100644 index 0000000000..6b4084cf3b --- /dev/null +++ b/packages/canon/docs/components/Title/styles.css @@ -0,0 +1,44 @@ +/* + * 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. + */ + +.sb-title { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + margin: 0; + font-weight: 500; + border: none; + + &.h1 { + font-size: 36px; + line-height: 44px; + margin-bottom: 8px; + margin-top: 0px; + } + + &.h2 { + font-size: 24px; + line-height: 32px; + margin-bottom: 12px; + margin-top: 52px; + } + + &.h3 { + font-size: 20px; + line-height: 28px; + margin-bottom: 12px; + margin-top: 40px; + } +} diff --git a/packages/canon/docs/components/index.ts b/packages/canon/docs/components/index.ts new file mode 100644 index 0000000000..0e5ff2e325 --- /dev/null +++ b/packages/canon/docs/components/index.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +export * from './Banner'; +export * from './Chip'; +export * from './Columns'; +export * from './ComponentStatus'; +export * from './IconLibrary'; +export * from './LayoutComponents'; +export * from './PropsTable'; +export * from './Roadmap'; +export * from './Table'; +export * from './Text'; +export * from './Title'; diff --git a/packages/canon/docs/components/styles.css b/packages/canon/docs/components/styles.css new file mode 100644 index 0000000000..670b0c3046 --- /dev/null +++ b/packages/canon/docs/components/styles.css @@ -0,0 +1,10 @@ +@import './Banner/styles.css'; +@import './Chip/styles.css'; +@import './Columns/styles.css'; +@import './ComponentStatus/styles.css'; +@import './IconLibrary/styles.css'; +@import './LayoutComponents/styles.css'; +@import './Roadmap/styles.css'; +@import './Table/styles.css'; +@import './Text/styles.css'; +@import './Title/styles.css'; diff --git a/packages/canon/docs/utils/argTypes.ts b/packages/canon/docs/utils/argTypes.ts new file mode 100644 index 0000000000..e6a68008f8 --- /dev/null +++ b/packages/canon/docs/utils/argTypes.ts @@ -0,0 +1,69 @@ +/* + * 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 { boxProperties } from '../../src/components/Box/sprinkles.css'; +import { + colorProperties, + spacingProperties, +} from '../../src/layout/sprinkles.css'; + +export const listResponsiveValues = ( + value: keyof typeof boxProperties.styles, +) => { + const values = boxProperties.styles[value]; + + if (!values) { + console.warn(`Value "${value}" not found in boxProperties.styles`); + return []; + } + + if ('values' in values) { + return Object.keys(values.values); + } + + return []; +}; + +export const listColorValues = (value: keyof typeof colorProperties.styles) => { + const values = colorProperties.styles[value]; + + if ('values' in values) { + return Object.keys(values.values); + } + + return []; +}; + +export const argTypesSpacing = Object.keys(spacingProperties.styles).reduce< + Record +>((acc, n) => { + acc[n] = { + control: 'inline-radio', + options: ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'], + }; + return acc; +}, {}); + +export const argTypesColor = Object.keys(colorProperties.styles).reduce< + Record +>((acc, n) => { + acc[n as keyof typeof colorProperties.styles] = { + control: 'select', + options: Object.keys( + colorProperties.styles[n as keyof typeof colorProperties.styles].values, + ), + }; + return acc; +}, {}); diff --git a/packages/canon/header.png b/packages/canon/header.png new file mode 100644 index 0000000000..507bd05ca7 Binary files /dev/null and b/packages/canon/header.png differ diff --git a/packages/canon/package.json b/packages/canon/package.json new file mode 100644 index 0000000000..7bfc717b74 --- /dev/null +++ b/packages/canon/package.json @@ -0,0 +1,81 @@ +{ + "name": "@backstage/canon", + "version": "0.0.0", + "backstage": { + "role": "web-library" + }, + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "private": true, + "keywords": [ + "backstage" + ], + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "packages/canon" + }, + "license": "Apache-2.0", + "sideEffects": false, + "main": "src/index.ts", + "types": "src/index.ts", + "files": [ + "dist" + ], + "scripts": { + "build": "backstage-cli package build", + "build-storybook": "storybook build", + "clean": "backstage-cli package clean", + "lint": "backstage-cli package lint", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack", + "start": "storybook dev -p 6006", + "test": "backstage-cli package test" + }, + "dependencies": { + "@base_ui/react": "^1.0.0-alpha.3", + "@remixicon/react": "^4.5.0", + "@vanilla-extract/sprinkles": "^1.6.3" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@chromatic-com/storybook": "^3.2.2", + "@storybook/addon-essentials": "^8.4.6", + "@storybook/addon-interactions": "^8.4.6", + "@storybook/addon-styling-webpack": "^1.0.1", + "@storybook/addon-themes": "^8.4.6", + "@storybook/addon-webpack5-compiler-swc": "^1.0.5", + "@storybook/blocks": "^8.4.6", + "@storybook/react": "^8.4.6", + "@storybook/react-webpack5": "^8.4.6", + "@storybook/test": "^8.4.6", + "@testing-library/jest-dom": "^6.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@vanilla-extract/rollup-plugin": "^1.3.10", + "@vanilla-extract/webpack-plugin": "^2.3.14", + "eslint-plugin-storybook": "^0.11.1", + "globals": "^15.11.0", + "mini-css-extract-plugin": "^2.9.2", + "react": "^18.0.2", + "react-dom": "^18.0.2", + "react-router-dom": "^6.3.0", + "storybook": "^8.4.6", + "webpack-merge": "^6.0.1" + }, + "peerDependencies": { + "@types/react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0", + "react-router-dom": "6.0.0-beta.0 || ^6.3.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } +} diff --git a/packages/canon/report.api.md b/packages/canon/report.api.md new file mode 100644 index 0000000000..247965bc05 --- /dev/null +++ b/packages/canon/report.api.md @@ -0,0 +1,518 @@ +## API Report File for "@backstage/canon" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +import { ForwardRefExoticComponent } from 'react'; +import { default as React_2 } from 'react'; +import * as React_3 from 'react'; +import { RefAttributes } from 'react'; + +// @public (undocumented) +export type AlignItemsProps = + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | Partial< + Record + >; + +// @public (undocumented) +export type AsProps = + | 'div' + | 'span' + | 'p' + | 'article' + | 'section' + | 'main' + | 'nav' + | 'aside' + | 'ul' + | 'ol' + | 'li' + | 'details' + | 'summary' + | 'dd' + | 'dl' + | 'dt'; + +// @public (undocumented) +export type Background = + | 'background' + | 'elevation1' + | 'elevation2' + | 'transparent' + | Partial< + Record + >; + +// @public (undocumented) +export type BorderRadiusProps = + | 'none' + | 'small' + | 'medium' + | 'full' + | Partial>; + +// @public (undocumented) +export const Box: ForwardRefExoticComponent< + BoxProps & RefAttributes +>; + +// @public (undocumented) +export interface BoxProps extends SpaceProps, ColorProps { + // (undocumented) + alignItems?: AlignItemsProps; + // (undocumented) + as?: keyof JSX.IntrinsicElements; + // (undocumented) + borderRadius?: BorderRadiusProps; + // (undocumented) + children?: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + display?: DisplayProps; + // (undocumented) + flexDirection?: FlexDirectionProps; + // (undocumented) + flexWrap?: FlexWrapProps; + // (undocumented) + justifyContent?: JustifyContentProps; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export type Breakpoint = keyof typeof breakpoints; + +// @public (undocumented) +export const breakpoints: { + xs: {}; + sm: { + '@media': string; + }; + md: { + '@media': string; + }; + lg: { + '@media': string; + }; + xl: { + '@media': string; + }; + '2xl': { + '@media': string; + }; +}; + +// @public (undocumented) +export const Button: React_2.ForwardRefExoticComponent< + ButtonProps & React_2.RefAttributes +>; + +// @public +export interface ButtonProps { + // (undocumented) + children: React_2.ReactNode; + // (undocumented) + disabled?: boolean; + // (undocumented) + iconEnd?: IconNames; + // (undocumented) + iconStart?: IconNames; + // (undocumented) + size?: 'small' | 'medium'; + // (undocumented) + variant?: 'primary' | 'secondary' | 'tertiary'; +} + +// @public (undocumented) +export const Checkbox: React_2.ForwardRefExoticComponent< + CheckboxProps & React_2.RefAttributes +>; + +// @public (undocumented) +export interface CheckboxProps { + // (undocumented) + checked?: boolean; + // (undocumented) + className?: string; + // (undocumented) + defaultChecked?: boolean; + // (undocumented) + disabled?: boolean; + // (undocumented) + label?: string; + // (undocumented) + name?: string; + // (undocumented) + onChange?: (checked: boolean) => void; + // (undocumented) + required?: boolean; + // (undocumented) + style?: React.CSSProperties; + // (undocumented) + value?: string; +} + +// @public (undocumented) +export type Color = + | 'primary' + | 'secondary' + | 'error' + | Partial>; + +// @public (undocumented) +export interface ColorProps { + // (undocumented) + background?: Background; + // (undocumented) + color?: Color; +} + +// @public (undocumented) +export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + +// @public (undocumented) +export const Container: React_2.ForwardRefExoticComponent< + ContainerProps & React_2.RefAttributes +>; + +// @public (undocumented) +export interface ContainerProps + extends Omit< + SpaceProps, + | 'padding' + | 'paddingLeft' + | 'paddingRight' + | 'paddingX' + | 'margin' + | 'marginLeft' + | 'marginRight' + | 'marginX' + | 'gap' + > { + // (undocumented) + children?: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export type DisplayProps = + | 'flex' + | 'none' + | 'inline' + | 'block' + | Partial>; + +// @public (undocumented) +export type FlexDirectionProps = + | 'row' + | 'column' + | Partial>; + +// @public (undocumented) +export type FlexWrapProps = + | 'wrap' + | 'nowrap' + | Partial>; + +// @public (undocumented) +export type Gap = Space | Partial>; + +// @public (undocumented) +export const Grid: ForwardRefExoticComponent< + GridProps & RefAttributes +> & { + Item: ForwardRefExoticComponent< + GridItemProps & RefAttributes + >; +}; + +// @public (undocumented) +export interface GridItemProps { + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + colSpan?: Columns | 'full'; + // (undocumented) + end?: Columns | 'auto'; + // (undocumented) + rowSpan?: Columns | 'full'; + // (undocumented) + start?: Columns | 'auto'; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export interface GridProps extends SpaceProps, ColorProps { + // (undocumented) + children?: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + columns?: Columns | Partial>; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export const Icon: (props: IconProps) => React_2.JSX.Element; + +// @public (undocumented) +export type IconMap = Partial>; + +// @public (undocumented) +export type IconNames = + | 'arrowDown' + | 'arrowLeft' + | 'arrowRight' + | 'arrowUp' + | 'arrowDownCircle' + | 'arrowLeftCircle' + | 'arrowRightCircle' + | 'arrowUpCircle' + | 'check' + | 'chevronDown' + | 'chevronLeft' + | 'chevronRight' + | 'chevronUp' + | 'cloud' + | 'heart' + | 'plus' + | 'trash'; + +// @public (undocumented) +export type IconProps = { + name: IconNames; + size?: number; +}; + +// @public (undocumented) +export const Inline: ForwardRefExoticComponent< + InlineProps & RefAttributes +>; + +// @public (undocumented) +export interface InlineProps extends SpaceProps, ColorProps { + // (undocumented) + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + // (undocumented) + alignY?: + | 'top' + | 'center' + | 'bottom' + | Partial>; + // (undocumented) + as?: AsProps; + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export type JustifyContentProps = + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | 'space-around' + | 'space-between' + | Partial< + Record< + Breakpoint, + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | 'space-around' + | 'space-between' + > + >; + +// @public (undocumented) +export type Margin = Space | Partial>; + +// @public (undocumented) +export type MarginBottom = Space | Partial>; + +// @public (undocumented) +export type MarginLeft = Space | Partial>; + +// @public (undocumented) +export type MarginRight = Space | Partial>; + +// @public (undocumented) +export type MarginTop = Space | Partial>; + +// @public (undocumented) +export type MarginX = Space | Partial>; + +// @public (undocumented) +export type MarginY = Space | Partial>; + +// @public (undocumented) +export type Padding = Space | Partial>; + +// @public (undocumented) +export type PaddingBottom = Space | Partial>; + +// @public (undocumented) +export type PaddingLeft = Space | Partial>; + +// @public (undocumented) +export type PaddingRight = Space | Partial>; + +// @public (undocumented) +export type PaddingTop = Space | Partial>; + +// @public (undocumented) +export type PaddingX = Space | Partial>; + +// @public (undocumented) +export type PaddingY = Space | Partial>; + +// @public (undocumented) +export type Space = keyof typeof space; + +// @public (undocumented) +export const space: { + none: number; + '2xs': string; + xs: string; + sm: string; + md: string; + lg: string; + xl: string; + '2xl': string; +}; + +// @public (undocumented) +export interface SpaceProps { + // (undocumented) + gap?: Gap; + // (undocumented) + margin?: Margin; + // (undocumented) + marginBottom?: MarginBottom; + // (undocumented) + marginLeft?: MarginLeft; + // (undocumented) + marginRight?: MarginRight; + // (undocumented) + marginTop?: MarginTop; + // (undocumented) + marginX?: MarginX; + // (undocumented) + marginY?: MarginY; + // (undocumented) + padding?: Padding; + // (undocumented) + paddingBottom?: PaddingBottom; + // (undocumented) + paddingLeft?: PaddingLeft; + // (undocumented) + paddingRight?: PaddingRight; + // (undocumented) + paddingTop?: PaddingTop; + // (undocumented) + paddingX?: PaddingX; + // (undocumented) + paddingY?: PaddingY; +} + +// @public (undocumented) +export const Stack: ForwardRefExoticComponent< + StackProps & RefAttributes +>; + +// @public (undocumented) +export interface StackProps extends SpaceProps, ColorProps { + // (undocumented) + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + // (undocumented) + as?: AsProps; + // (undocumented) + children: React.ReactNode; + // (undocumented) + className?: string; + // (undocumented) + style?: React.CSSProperties; +} + +// @public (undocumented) +export const Table: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableBody: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableCell: React_3.ForwardRefExoticComponent< + React_3.TdHTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableFooter: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableHead: React_3.ForwardRefExoticComponent< + React_3.ThHTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableHeader: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export const TableRow: React_3.ForwardRefExoticComponent< + React_3.HTMLAttributes & + React_3.RefAttributes +>; + +// @public (undocumented) +export type Theme = keyof typeof themes; + +// @public (undocumented) +export const themes: { + light: { + selector: string; + }; + dark: { + selector: string; + }; +}; +``` diff --git a/packages/canon/src/components/Box/Box.stories.tsx b/packages/canon/src/components/Box/Box.stories.tsx new file mode 100644 index 0000000000..6f15d984e1 --- /dev/null +++ b/packages/canon/src/components/Box/Box.stories.tsx @@ -0,0 +1,183 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Box } from './Box'; +import { + listResponsiveValues, + argTypesSpacing, + argTypesColor, +} from '../../../docs/utils/argTypes'; +import { boxProperties } from './sprinkles.css'; + +const argTypesBox = Object.keys(boxProperties.styles).reduce< + Record +>((acc, n) => { + acc[n] = { + control: 'select', + options: listResponsiveValues(n as keyof typeof boxProperties.styles), + }; + return acc; +}, {}); + +const meta = { + title: 'Components/Box', + component: Box, + parameters: { + layout: 'centered', + }, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + ...argTypesBox, + as: { + control: { type: 'select' }, + options: ['div', 'span', 'article', 'section'], + }, + children: { + control: false, + }, + }, + args: { + as: 'div', + background: 'elevation1', + borderRadius: 'small', + children: 'Basic Box', + display: 'block', + padding: 'sm', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Basic: Story = { + args: {}, +}; + +export const Responsive: Story = { + render: () => ( + + Responsive Box + + ), +}; + +export const FlexContainer: Story = { + render: () => ( + + + Item 1 + + + Item 2 + + + Item 3 + + + ), +}; + +export const Nested: Story = { + render: () => ( + + + Header + + + + Sidebar + + + Main Content + + + + Footer + + + ), +}; + +export const Alignment: Story = { + render: () => ( + + + Centered Content + + + ), +}; + +// Example showing different spacing combinations +export const Spacing: Story = { + render: () => ( + + + Small Padding + + + Medium Padding + + + Large Padding + + + Mixed Padding + + + ), +}; + +// Example showing different display values +export const DisplayVariants: Story = { + render: () => ( + + + Display Block + + + Display Flex + + + Display Inline + + + ), +}; diff --git a/packages/canon/src/components/Box/Box.tsx b/packages/canon/src/components/Box/Box.tsx new file mode 100644 index 0000000000..ecf138f1ce --- /dev/null +++ b/packages/canon/src/components/Box/Box.tsx @@ -0,0 +1,39 @@ +/* + * 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 { createElement, forwardRef } from 'react'; +import { boxSprinkles } from './sprinkles.css'; +import { BoxProps } from './types'; + +/** @public */ +export const Box = forwardRef((props, ref) => { + const { as = 'div', className, style, children, ...restProps } = props; + + // Generate the list of class names + const sprinklesClassName = boxSprinkles(restProps); + + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = ['box', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement(as, { + ref, + className: classNames, + style, + children, + }); +}); diff --git a/packages/canon/src/components/Box/Docs.mdx b/packages/canon/src/components/Box/Docs.mdx new file mode 100644 index 0000000000..af9cd9be76 --- /dev/null +++ b/packages/canon/src/components/Box/Docs.mdx @@ -0,0 +1,83 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as BoxStories from './Box.stories'; +import { Title, Text } from '../../../docs/components'; +import { Padding } from './docs/padding'; +import { PropsTable, getProps } from '../../../docs/components'; +import { boxProperties } from './sprinkles.css'; +import { spacingProperties } from '../../layout/sprinkles.css'; + + + + + +Box + + Box is the lowest-level component in Canon. We use it internally to build all + of our components. It provides a consistent API for styling and layout. + + +Usage +Hello World! +`} language="tsx" dark /> + +API reference + +Box + + This is the Box component, our lowest-level component. Here are all the + available properties. + + + + + + Padding and margin are used to create space around your component using our + predefined spacing tokens. We would recommend to use padding over margin to + avoid collapsing margins but both are available. + + + + + + +Examples +Here are some examples of how you can use the Box component. + +Simple example +A simple example of how to use the Box component. +Hello World`} + language="tsx" + dark +/> + +Responsive + + Most of the values can be defined per breakpoint, making it easy to create + responsive designs. + +Hello World`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Box/docs/padding.tsx b/packages/canon/src/components/Box/docs/padding.tsx new file mode 100644 index 0000000000..86a7c801a2 --- /dev/null +++ b/packages/canon/src/components/Box/docs/padding.tsx @@ -0,0 +1,107 @@ +/* + * 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 React from 'react'; +import { Inline } from '../../Inline'; +import { Box } from '../Box'; + +const FakeBox = ({ children }: { children: string }) => ( + + {children} + +); + +export const Padding = () => { + return ( + + + + padding + + + paddingX + + + paddingY + + + + + paddingTop + + + paddingBottom + + + paddingLeft + + + paddingRight + + + + ); +}; diff --git a/packages/canon/src/components/Box/index.tsx b/packages/canon/src/components/Box/index.tsx new file mode 100644 index 0000000000..e4f1867edc --- /dev/null +++ b/packages/canon/src/components/Box/index.tsx @@ -0,0 +1,18 @@ +/* + * 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. + */ +export { Box } from './Box'; +export type * from './types'; +export { breakpoints, space, themes } from '../../layout/properties'; diff --git a/packages/canon/src/components/Box/sprinkles.css.ts b/packages/canon/src/components/Box/sprinkles.css.ts new file mode 100644 index 0000000000..df5664029b --- /dev/null +++ b/packages/canon/src/components/Box/sprinkles.css.ts @@ -0,0 +1,61 @@ +/* + * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +export const boxProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'], + properties: { + flexDirection: ['row', 'column'], + justifyContent: [ + 'stretch', + 'flex-start', + 'center', + 'flex-end', + 'space-around', + 'space-between', + ], + alignItems: ['stretch', 'flex-start', 'center', 'flex-end'], + borderRadius: { + none: 0, + small: '4px', + medium: '8px', + full: '9999px', + }, + boxShadow: { + small: 'var(--canon-box-shadow-small)', + medium: 'var(--canon-box-shadow-medium)', + large: 'var(--canon-box-shadow-large)', + }, + border: { + none: 'none', + thin: '1px solid var(--canon-outline)', + error: '1px solid var(--canon-error)', + }, + display: ['none', 'flex', 'block', 'inline'], + flexWrap: ['wrap', 'nowrap'], + }, +}); + +export const boxSprinkles = createSprinkles( + spacingProperties, + boxProperties, + colorProperties, +); diff --git a/packages/canon/src/components/Box/styles.css b/packages/canon/src/components/Box/styles.css new file mode 100644 index 0000000000..75fd0dd493 --- /dev/null +++ b/packages/canon/src/components/Box/styles.css @@ -0,0 +1,4 @@ +.box { + font-family: 'var(--canon-font-regular)'; + color: 'var(--canon-text-primary)'; +} diff --git a/packages/canon/src/components/Box/types.ts b/packages/canon/src/components/Box/types.ts new file mode 100644 index 0000000000..2ba5929fdd --- /dev/null +++ b/packages/canon/src/components/Box/types.ts @@ -0,0 +1,89 @@ +/* + * 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 { Breakpoint, SpaceProps, ColorProps } from '../../layout/types'; + +/** @public */ +export type DisplayProps = + | 'flex' + | 'none' + | 'inline' + | 'block' + | Partial>; + +/** @public */ +export type FlexDirectionProps = + | 'row' + | 'column' + | Partial>; + +/** @public */ +export type FlexWrapProps = + | 'wrap' + | 'nowrap' + | Partial>; + +/** @public */ +export type JustifyContentProps = + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | 'space-around' + | 'space-between' + | Partial< + Record< + Breakpoint, + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | 'space-around' + | 'space-between' + > + >; + +/** @public */ +export type AlignItemsProps = + | 'stretch' + | 'flex-start' + | 'center' + | 'flex-end' + | Partial< + Record + >; + +/** @public */ +export type BorderRadiusProps = + | 'none' + | 'small' + | 'medium' + | 'full' + | Partial>; + +/** @public */ +export interface BoxProps extends SpaceProps, ColorProps { + as?: keyof JSX.IntrinsicElements; + children?: React.ReactNode; + display?: DisplayProps; + flexDirection?: FlexDirectionProps; + flexWrap?: FlexWrapProps; + justifyContent?: JustifyContentProps; + alignItems?: AlignItemsProps; + borderRadius?: BorderRadiusProps; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Button/Button.stories.tsx b/packages/canon/src/components/Button/Button.stories.tsx new file mode 100644 index 0000000000..6cab1cd1ba --- /dev/null +++ b/packages/canon/src/components/Button/Button.stories.tsx @@ -0,0 +1,106 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Button } from './Button'; +import { Inline } from '../Inline'; +import { Stack } from '../Stack'; + +const meta = { + title: 'Components/Button', + component: Button, + parameters: { + layout: 'centered', + }, + argTypes: { + size: { + control: 'select', + options: ['small', 'medium'], + }, + }, + args: { + size: 'medium', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + children: 'Primary button', + }, +}; + +export const Secondary: Story = { + args: { + children: 'Secondary button', + variant: 'secondary', + }, +}; + +export const Tertiary: Story = { + args: { + children: 'Tertiary button', + variant: 'tertiary', + }, +}; + +export const Sizes: Story = { + args: { + children: 'Button', + }, + render: args => ( + + + ); + }, +); + +export default Button; diff --git a/packages/canon/src/components/Button/Docs.mdx b/packages/canon/src/components/Button/Docs.mdx new file mode 100644 index 0000000000..9f0e623c55 --- /dev/null +++ b/packages/canon/src/components/Button/Docs.mdx @@ -0,0 +1,54 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as ButtonStories from './Button.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable/PropsTable'; + + + + + +Button +A button component that can be used to trigger actions. + + + +Usage +Click me +`} language="tsx" dark /> + + + API reference + + + + + diff --git a/packages/canon/src/components/Button/index.tsx b/packages/canon/src/components/Button/index.tsx new file mode 100644 index 0000000000..bc6714754d --- /dev/null +++ b/packages/canon/src/components/Button/index.tsx @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Button } from './Button'; +export type { ButtonProps } from './Button'; diff --git a/packages/canon/src/components/Button/styles.css b/packages/canon/src/components/Button/styles.css new file mode 100644 index 0000000000..8ebb58ffeb --- /dev/null +++ b/packages/canon/src/components/Button/styles.css @@ -0,0 +1,82 @@ +/* + * 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. + */ + +.button { + all: unset; + display: inline-flex; + align-items: center; + justify-content: center; + user-select: none; + font-family: var(--canon-font-regular); + font-weight: var(--canon-font-bold); + font-size: var(--canon-font-size-md); + padding: 0; + transition: all 150ms ease; + cursor: pointer; + border-radius: 8px; +} + +.button.primary { + background-color: var(--canon-accent); + color: var(--canon-text-primary-on-accent); +} + +.button.primary:hover { + background-color: transparent; + box-shadow: inset 0 0 0 1px var(--canon-outline-focus); + color: var(--canon-text-primary); +} + +.button.secondary { + background-color: transparent; + box-shadow: inset 0 0 0 1px var(--canon-outline); + color: var(--canon-text-primary); +} + +.button.secondary:hover { + box-shadow: inset 0 0 0 1px var(--canon-outline-hover); +} + +.button.tertiary { + background-color: transparent; + color: var(--canon-text-primary); +} + +.button.tertiary:hover { + color: var(--canon-text-secondary); +} + +.button.small { + padding-left: 6px; + padding-right: 6px; + height: 32px; +} + +.button.medium { + padding-left: 8px; + padding-right: 8px; + height: 40px; +} + +.button-content { + display: flex; + align-items: center; + gap: var(--canon-spacing-xs); +} + +.button-content.icon-both { + flex: 1; +} diff --git a/packages/canon/src/components/Checkbox/Checkbox.stories.tsx b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx new file mode 100644 index 0000000000..ffd874ffe7 --- /dev/null +++ b/packages/canon/src/components/Checkbox/Checkbox.stories.tsx @@ -0,0 +1,35 @@ +/* + * 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 { Checkbox } from './Checkbox'; + +const meta = { + title: 'Components/Checkbox', + component: Checkbox, + parameters: { + layout: 'centered', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + label: 'Accept terms and conditions', + }, +}; diff --git a/packages/canon/src/components/Checkbox/Checkbox.tsx b/packages/canon/src/components/Checkbox/Checkbox.tsx new file mode 100644 index 0000000000..3021032421 --- /dev/null +++ b/packages/canon/src/components/Checkbox/Checkbox.tsx @@ -0,0 +1,64 @@ +/* + * 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 React from 'react'; + +import { CheckboxRoot, CheckboxIndicator } from '@base_ui/react'; +import { Icon } from '@backstage/canon'; +import type { CheckboxProps } from './types'; + +/** @public */ +export const Checkbox = React.forwardRef( + (props, ref) => { + const { + label, + checked, + onChange, + disabled, + required, + className, + name, + value, + style, + } = props; + + const checkboxElement = ( + + + + + + ); + + return label ? ( + + ) : ( + checkboxElement + ); + }, +); diff --git a/packages/canon/src/components/Checkbox/Docs.mdx b/packages/canon/src/components/Checkbox/Docs.mdx new file mode 100644 index 0000000000..12e13abf03 --- /dev/null +++ b/packages/canon/src/components/Checkbox/Docs.mdx @@ -0,0 +1,70 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as CheckboxStories from './Checkbox.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable'; + + + + + +Checkbox +A checkbox component that can be used to trigger actions. + + + +Usage + +`} language="tsx" dark /> + + + API reference + + + void", + responsive: false, + }, + disabled: { + type: 'boolean', + responsive: false, + }, + required: { + type: 'boolean', + responsive: false, + }, + name: { + type: 'string', + responsive: false, + }, + value: { + type: 'string', + responsive: false, + }, + className: { + type: 'string', + responsive: false, + }, + style: { + type: 'CSSProperties', + responsive: false, + }, + }} +/> + + diff --git a/packages/canon/src/components/Checkbox/index.ts b/packages/canon/src/components/Checkbox/index.ts new file mode 100644 index 0000000000..f6dfbf6beb --- /dev/null +++ b/packages/canon/src/components/Checkbox/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Checkbox } from './Checkbox'; +export type { CheckboxProps } from './types'; diff --git a/packages/canon/src/components/Checkbox/styles.css b/packages/canon/src/components/Checkbox/styles.css new file mode 100644 index 0000000000..e4ac30a447 --- /dev/null +++ b/packages/canon/src/components/Checkbox/styles.css @@ -0,0 +1,47 @@ +.checkbox-label { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + gap: var(--canon-spacing-xs); + font-size: var(--canon-font-size-xs); + font-family: var(--canon-font-regular); + color: var(--canon-text-primary); + user-select: none; + + & .checkbox { + all: unset; + display: flex; + align-items: center; + justify-content: center; + width: 16px; + height: 16px; + box-shadow: inset 0 0 0 1px var(--canon-outline); + cursor: pointer; + border-radius: 2px; + transition: all 0.2s ease-in-out; + + &[data-state='unchecked'] { + & .checkbox-indicator { + display: none; + } + } + + &[data-state='checked'] { + background: var(--canon-accent); + } + } + + & .checkbox-indicator { + display: flex; + align-items: center; + justify-content: center; + color: var(--canon-text-primary-on-accent); + } + + &:hover { + & .checkbox { + box-shadow: inset 0 0 0 1px var(--canon-outline-hover); + } + } +} diff --git a/packages/canon/src/components/Checkbox/types.ts b/packages/canon/src/components/Checkbox/types.ts new file mode 100644 index 0000000000..0240954afa --- /dev/null +++ b/packages/canon/src/components/Checkbox/types.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +/** @public */ +export interface CheckboxProps { + label?: string; + defaultChecked?: boolean; + checked?: boolean; + onChange?: (checked: boolean) => void; + disabled?: boolean; + required?: boolean; + className?: string; + name?: string; + value?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Container/Container.stories.tsx b/packages/canon/src/components/Container/Container.stories.tsx new file mode 100644 index 0000000000..bedf96ec9e --- /dev/null +++ b/packages/canon/src/components/Container/Container.stories.tsx @@ -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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Box } from '../Box/Box'; +import { argTypesSpacing } from '../../../docs/utils/argTypes'; +import { Container } from './Container'; + +const argTypesSpacingWithoutLeftAndRight = { ...argTypesSpacing }; +delete argTypesSpacingWithoutLeftAndRight.padding; +delete argTypesSpacingWithoutLeftAndRight.paddingLeft; +delete argTypesSpacingWithoutLeftAndRight.paddingRight; +delete argTypesSpacingWithoutLeftAndRight.paddingX; +delete argTypesSpacingWithoutLeftAndRight.margin; +delete argTypesSpacingWithoutLeftAndRight.marginLeft; +delete argTypesSpacingWithoutLeftAndRight.marginRight; +delete argTypesSpacingWithoutLeftAndRight.marginX; +delete argTypesSpacingWithoutLeftAndRight.gap; + +const meta = { + title: 'Components/Container', + component: Container, + argTypes: { + ...argTypesSpacingWithoutLeftAndRight, + children: { + control: false, + }, + className: { + control: 'text', + }, + }, + parameters: { + layout: 'fullscreen', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const FakeBox = () => ( + +); + +export const Default: Story = { + args: {}, + render: args => ( + + + + ), +}; diff --git a/packages/canon/src/components/Container/Container.tsx b/packages/canon/src/components/Container/Container.tsx new file mode 100644 index 0000000000..b27775e116 --- /dev/null +++ b/packages/canon/src/components/Container/Container.tsx @@ -0,0 +1,37 @@ +/* + * 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 React, { forwardRef } from 'react'; +import { containerSprinkles } from './sprinkles.css'; +import { ContainerProps } from './types'; + +/** @public */ +export const Container = forwardRef( + (props, ref) => { + const { children, className, style, ...restProps } = props; + + const containerClassName = containerSprinkles(restProps); + + return ( +
+ {children} +
+ ); + }, +); diff --git a/packages/canon/src/components/Container/Docs.mdx b/packages/canon/src/components/Container/Docs.mdx new file mode 100644 index 0000000000..ca81477d44 --- /dev/null +++ b/packages/canon/src/components/Container/Docs.mdx @@ -0,0 +1,77 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as ContainerStories from './Container.stories'; +import { Title, Text, PropsTable, getProps } from '../../../docs/components'; +import { spacingProperties } from '../../layout/sprinkles.css'; +import { containerProperties } from './sprinkles.css'; + + + + + +Container + + + The container component let you use our default max-width and center the + content on the page. + + +Usage +Hello World! +`} language="tsx" dark /> + + + API reference + + + + +Examples + +Simple +A simple example of how to use the Container component. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Responsive padding & margin + + The Container component also supports responsive values, making it easy to + create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Container/index.tsx b/packages/canon/src/components/Container/index.tsx new file mode 100644 index 0000000000..81614c352d --- /dev/null +++ b/packages/canon/src/components/Container/index.tsx @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Container } from './Container'; +export type { ContainerProps } from './types'; diff --git a/packages/canon/src/components/Container/sprinkles.css.ts b/packages/canon/src/components/Container/sprinkles.css.ts new file mode 100644 index 0000000000..989e369433 --- /dev/null +++ b/packages/canon/src/components/Container/sprinkles.css.ts @@ -0,0 +1,40 @@ +/* + * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints, space } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +export const containerProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + paddingTop: space, + paddingBottom: space, + marginTop: space, + marginBottom: space, + }, + shorthands: { + paddingY: ['paddingTop', 'paddingBottom'], + marginY: ['marginTop', 'marginBottom'], + }, +}); + +export const containerSprinkles = createSprinkles( + spacingProperties, + colorProperties, + containerProperties, +); diff --git a/packages/canon/src/components/Container/styles.css b/packages/canon/src/components/Container/styles.css new file mode 100644 index 0000000000..4da813623f --- /dev/null +++ b/packages/canon/src/components/Container/styles.css @@ -0,0 +1,5 @@ +.container { + max-width: var(--canon-container-max-width); + margin: 0 auto; + padding: 0 var(--canon-container-padding); +} diff --git a/packages/canon/src/components/Container/types.ts b/packages/canon/src/components/Container/types.ts new file mode 100644 index 0000000000..b1f414cf30 --- /dev/null +++ b/packages/canon/src/components/Container/types.ts @@ -0,0 +1,35 @@ +/* + * 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 { SpaceProps } from '../../layout/types'; + +/** @public */ +export interface ContainerProps + extends Omit< + SpaceProps, + | 'padding' + | 'paddingLeft' + | 'paddingRight' + | 'paddingX' + | 'margin' + | 'marginLeft' + | 'marginRight' + | 'marginX' + | 'gap' + > { + children?: React.ReactNode; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Grid/Docs.mdx b/packages/canon/src/components/Grid/Docs.mdx new file mode 100644 index 0000000000..14e3bfb922 --- /dev/null +++ b/packages/canon/src/components/Grid/Docs.mdx @@ -0,0 +1,199 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as GridStories from './Grid.stories'; +import { Title, Text, PropsTable, getProps } from '../../../docs/components'; +import { spacingProperties } from '../../layout/sprinkles.css'; + + + + + +Grid + + A layout component that helps to create simple column-based layouts as well as + more complex ones. + + +Usage + + Hello World + +`} language="tsx" dark /> + +API reference + +Grid + + This is the grid 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. + + + + + + The grid component also accepts all the spacing props from the Box component. + + + + +Grid Item + + If you need more control over the columns, you can use the grid item + component. This will give you access to `rowSpan`, `colSpan`, `start` and + `end`. All values are responsive. This component is optional, you can use any + elements directly if you prefer. + + + + +Examples + +Simple grid +This is a simple grid with 3 columns and a gap of md. + + Hello World + Hello World + Hello World + +`} + language="tsx" + dark +/> + +Complex grid + + You can also use the grid item to create more complex layouts. In this example + the first column will span 1 column and the second column will span 2 columns. + + + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Mixing rows and columns + + The grid item component also supports the `rowSpan` prop, which allows you to + span multiple rows within the grid layout. In this example, the first item + will span 2 rows to achieve a dynamic and flexible grid structure. + + + + + Hello World + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Responsive + + The grid component also supports responsive values. In this example the grid + will have 1 column on small screens and 3 on large screens, with a gap of xs + on small screens and md on large screens. + + + + Hello World + + + Hello World + + +`} + language="tsx" + dark +/> + +Start and End + + The start and end props can be used to position the item in the grid. + + + + Hello World + + +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Grid/Grid.stories.tsx b/packages/canon/src/components/Grid/Grid.stories.tsx new file mode 100644 index 0000000000..bf1bcecfd7 --- /dev/null +++ b/packages/canon/src/components/Grid/Grid.stories.tsx @@ -0,0 +1,121 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Grid } from './Grid'; +import type { GridItemProps } from './types'; +import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; +import { Stack } from '../Stack'; + +const meta = { + title: 'Components/Grid', + component: Grid, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + children: { + control: false, + }, + className: { + control: 'text', + }, + }, + args: { + gap: 'xs', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const FakeBox = () => ( + +); + +export const Default: Story = { + args: {}, + render: args => ( + + + + + + ), +}; + +export const LargeGap: Story = { + args: { + gap: 'lg', + }, + render: args => ( + + + + + + ), +}; + +export const ColumnSizes: Story = { + args: { + columns: 12, + gap: 'md', + }, + render: args => ( + + {Array.from({ length: 11 }, (_, i) => ( + + + + + + + + + ))} + + ), +}; + +export const RowAndColumns: Story = { + args: { + columns: 12, + gap: 'md', + }, + render: args => ( + + + + + + + + + + + + + + ), +}; diff --git a/packages/canon/src/components/Grid/Grid.tsx b/packages/canon/src/components/Grid/Grid.tsx new file mode 100644 index 0000000000..2b61d1d3d4 --- /dev/null +++ b/packages/canon/src/components/Grid/Grid.tsx @@ -0,0 +1,78 @@ +/* + * 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 { createElement, forwardRef } from 'react'; +import { GridItemProps, GridProps } from './types'; +import { gridItemSprinkles, gridSprinkles } from './sprinkles.css'; + +const GridBase = forwardRef((props, ref) => { + const { + children, + columns, + gap = 'xs', + className, + style, + ...restProps + } = props; + + const sprinklesClassName = gridSprinkles({ + ...restProps, + gap, + gridTemplateColumns: columns ? columns : 'auto', + }); + + const classNames = ['grid', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement( + 'div', + { + ref, + className: classNames, + style, + }, + children, + ); +}); + +const GridItem = forwardRef((props, ref) => { + const { children, rowSpan, colSpan, start, end, className, style } = props; + + const sprinklesClassName = gridItemSprinkles({ + rowSpan, + colSpan, + start, + end, + }); + + const classNames = ['grid-item', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement( + 'div', + { + ref, + className: classNames, + style, + }, + children, + ); +}); + +/** @public */ +export const Grid = Object.assign(GridBase, { Item: GridItem }); diff --git a/packages/canon/src/components/Grid/index.ts b/packages/canon/src/components/Grid/index.ts new file mode 100644 index 0000000000..b07249241c --- /dev/null +++ b/packages/canon/src/components/Grid/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Grid } from './Grid'; +export type { GridProps, GridItemProps, Columns } from './types'; diff --git a/packages/canon/src/components/Grid/sprinkles.css.ts b/packages/canon/src/components/Grid/sprinkles.css.ts new file mode 100644 index 0000000000..aff5a340ed --- /dev/null +++ b/packages/canon/src/components/Grid/sprinkles.css.ts @@ -0,0 +1,130 @@ +/* + * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +const gridProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + gridTemplateColumns: { + 1: 'repeat(1, minmax(0, 1fr))', + 2: 'repeat(2, minmax(0, 1fr))', + 3: 'repeat(3, minmax(0, 1fr))', + 4: 'repeat(4, minmax(0, 1fr))', + 5: 'repeat(5, minmax(0, 1fr))', + 6: 'repeat(6, minmax(0, 1fr))', + 7: 'repeat(7, minmax(0, 1fr))', + 8: 'repeat(8, minmax(0, 1fr))', + 9: 'repeat(9, minmax(0, 1fr))', + 10: 'repeat(10, minmax(0, 1fr))', + 11: 'repeat(11, minmax(0, 1fr))', + 12: 'repeat(12, minmax(0, 1fr))', + auto: 'repeat(auto-fit, minmax(0, 1fr))', + }, + }, + shorthands: { + columns: ['gridTemplateColumns'], + }, +}); + +export const gridSprinkles = createSprinkles( + spacingProperties, + colorProperties, + gridProperties, +); + +const gridItemProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + gridColumn: { + 1: 'span 1 / span 1', + 2: 'span 2 / span 2', + 3: 'span 3 / span 3', + 4: 'span 4 / span 4', + 5: 'span 5 / span 5', + 6: 'span 6 / span 6', + 7: 'span 7 / span 7', + 8: 'span 8 / span 8', + 9: 'span 9 / span 9', + 10: 'span 10 / span 10', + 11: 'span 11 / span 11', + 12: 'span 12 / span 12', + full: '1 / -1', + }, + gridRow: { + 1: 'span 1 / span 1', + 2: 'span 2 / span 2', + 3: 'span 3 / span 3', + 4: 'span 4 / span 4', + 5: 'span 5 / span 5', + 6: 'span 6 / span 6', + 7: 'span 7 / span 7', + 8: 'span 8 / span 8', + 9: 'span 9 / span 9', + 10: 'span 10 / span 10', + 11: 'span 11 / span 11', + 12: 'span 12 / span 12', + full: '1 / -1', + }, + gridColumnStart: { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13', + auto: 'auto', + }, + gridColumnEnd: { + 1: '1', + 2: '2', + 3: '3', + 4: '4', + 5: '5', + 6: '6', + 7: '7', + 8: '8', + 9: '9', + 10: '10', + 11: '11', + 12: '12', + 13: '13', + auto: 'auto', + }, + }, + shorthands: { + colSpan: ['gridColumn'], + rowSpan: ['gridRow'], + start: ['gridColumnStart'], + end: ['gridColumnEnd'], + }, +}); + +export const gridItemSprinkles = createSprinkles( + colorProperties, + gridItemProperties, +); diff --git a/packages/canon/src/components/Grid/styles.css b/packages/canon/src/components/Grid/styles.css new file mode 100644 index 0000000000..81f8d5471d --- /dev/null +++ b/packages/canon/src/components/Grid/styles.css @@ -0,0 +1,3 @@ +.grid { + display: grid; +} diff --git a/packages/canon/src/components/Grid/types.ts b/packages/canon/src/components/Grid/types.ts new file mode 100644 index 0000000000..87edbd75bf --- /dev/null +++ b/packages/canon/src/components/Grid/types.ts @@ -0,0 +1,39 @@ +/* + * 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 { Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +/** @public */ +export type Columns = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; + +/** @public */ +export interface GridProps extends SpaceProps, ColorProps { + children?: React.ReactNode; + columns?: Columns | Partial>; + className?: string; + style?: React.CSSProperties; +} + +/** @public */ +export interface GridItemProps { + children: React.ReactNode; + rowSpan?: Columns | 'full'; + colSpan?: Columns | 'full'; + start?: Columns | 'auto'; + end?: Columns | 'auto'; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Heading/Docs.mdx b/packages/canon/src/components/Heading/Docs.mdx new file mode 100644 index 0000000000..dd64bd59b2 --- /dev/null +++ b/packages/canon/src/components/Heading/Docs.mdx @@ -0,0 +1,83 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as HeadingStories from './Heading.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable/PropsTable'; + + + + + +Heading + +Headings are used to structure the content of your page. + + + +Usage +Hello World! +`} language="tsx" dark /> + + + API reference + + + + +Examples +Here are some examples of how you can use the Heading component. + +All variants + + The `Heading` component has a `variant` prop that can be used to change the + appearance of the heading. + + + + + + Title 1 Lorem ipsum dolor sit amet consectetur... + Title 2 Lorem ipsum dolor sit amet consectetur... + Title 3 Lorem ipsum dolor sit amet consectetur... + Title 4 Lorem ipsum dolor sit amet consectetur... + Title 5 Lorem ipsum dolor sit amet consectetur... + Display Lorem ipsum dolor sit amet consectetur... +`} + language="tsx" + dark +/> + +Responsive + + You can also use the `variant` prop to change the appearance of the text based + on the screen size. + + +Responsive Lorem ipsum dolor sit amet consectetur...`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Heading/Heading.stories.tsx b/packages/canon/src/components/Heading/Heading.stories.tsx new file mode 100644 index 0000000000..d956961503 --- /dev/null +++ b/packages/canon/src/components/Heading/Heading.stories.tsx @@ -0,0 +1,74 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Heading } from './Heading'; +import { Stack } from '../Stack'; + +const meta = { + title: 'Components/Heading', + component: Heading, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: 'Heading', + }, +}; + +export const Title1: Story = { + args: { + children: 'Look mum, no hands!', + variant: 'title1', + }, +}; + +export const AllVariants: Story = { + args: { + children: 'Heading', + }, + render: () => ( + + Display + Title 1 + Title 2 + Title 3 + Title 4 + + ), +}; + +export const Responsive: Story = { + args: { + ...Default.args, + variant: { + xs: 'title4', + sm: 'display', + }, + }, +}; + +export const CustomTag: Story = { + args: { + ...Default.args, + variant: 'title5', + as: 'h2', + }, +}; diff --git a/packages/canon/src/components/Heading/Heading.tsx b/packages/canon/src/components/Heading/Heading.tsx new file mode 100644 index 0000000000..6e45433b91 --- /dev/null +++ b/packages/canon/src/components/Heading/Heading.tsx @@ -0,0 +1,49 @@ +/* + * 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 React, { forwardRef } from 'react'; +import { HeadingProps } from './types'; +import { useTheme } from '../../theme/context'; +import { getResponsiveValue } from '../../utils/getResponsiveValue'; + +export const Heading = forwardRef( + (props, ref) => { + const { children, variant = 'title1', as = 'h1', ...restProps } = props; + const { breakpoint } = useTheme(); + const responsiveVariant = getResponsiveValue(variant, breakpoint); + + let Component = as; + if (variant === 'title2') Component = 'h2'; + if (variant === 'title3') Component = 'h3'; + if (variant === 'title4') Component = 'h4'; + if (variant === 'title5') Component = 'h5'; + if (as) Component = as; + + return ( + + {children} + + ); + }, +); + +Heading.displayName = 'Heading'; diff --git a/packages/canon/src/components/Heading/index.ts b/packages/canon/src/components/Heading/index.ts new file mode 100644 index 0000000000..69b7c3c1a0 --- /dev/null +++ b/packages/canon/src/components/Heading/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { Heading } from './Heading'; +export type { HeadingProps } from './types'; diff --git a/packages/canon/src/components/Heading/styles.css b/packages/canon/src/components/Heading/styles.css new file mode 100644 index 0000000000..d2d6a27576 --- /dev/null +++ b/packages/canon/src/components/Heading/styles.css @@ -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. + */ + +.text { + font-family: var(--canon-font-regular); + color: var(--canon-text-primary); + padding: 0; + margin: 0; + + &.text-display { + font-size: var(--canon-font-size-display); + line-height: 100%; + font-weight: var(--canon-font-bold); + } + + &.text-title1 { + font-size: var(--canon-font-size-title1); + line-height: 100%; + font-weight: var(--canon-font-bold); + } + + &.text-title2 { + font-size: var(--canon-font-size-title2); + line-height: 100%; + font-weight: var(--canon-font-bold); + } + + &.text-title3 { + font-size: var(--canon-font-size-title3); + line-height: 100%; + font-weight: var(--canon-font-bold); + } + + &.text-title4 { + font-size: var(--canon-font-size-title4); + line-height: 100%; + font-weight: var(--canon-font-bold); + } + + &.text-title5 { + font-size: var(--canon-font-size-title5); + line-height: 100%; + font-weight: var(--canon-font-bold); + } +} diff --git a/packages/canon/src/components/Heading/types.ts b/packages/canon/src/components/Heading/types.ts new file mode 100644 index 0000000000..fb37cf6414 --- /dev/null +++ b/packages/canon/src/components/Heading/types.ts @@ -0,0 +1,36 @@ +/* + * 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 { Breakpoint } from '../../layout/types'; + +/** @public */ +export interface HeadingProps { + children: React.ReactNode; + variant?: + | 'display' + | 'title1' + | 'title2' + | 'title3' + | 'title4' + | 'title5' + | Partial< + Record< + Breakpoint, + 'display' | 'title1' | 'title2' | 'title3' | 'title4' | 'title5' + > + >; + as?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; +} diff --git a/packages/canon/src/components/Icon/Docs.mdx b/packages/canon/src/components/Icon/Docs.mdx new file mode 100644 index 0000000000..463fe60133 --- /dev/null +++ b/packages/canon/src/components/Icon/Docs.mdx @@ -0,0 +1,48 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as IconStories from './Icon.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable/PropsTable'; +import { defaultIcons } from './icons'; + + + + + +Icon + +Icons are used to represent an action or a state. + + + +Usage + +`} language="tsx" dark /> + + + API reference + + + + + diff --git a/packages/canon/src/components/Icon/Icon.stories.tsx b/packages/canon/src/components/Icon/Icon.stories.tsx new file mode 100644 index 0000000000..61e837c5ed --- /dev/null +++ b/packages/canon/src/components/Icon/Icon.stories.tsx @@ -0,0 +1,60 @@ +/* + * 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 React from 'react'; +import { Meta, StoryObj } from '@storybook/react'; +import { Icon } from './Icon'; +import { ThemeProvider } from '../../theme/context'; +import { defaultIcons } from './icons'; + +const meta = { + title: 'Components/Icon', + component: Icon, + parameters: { + layout: 'centered', + }, + argTypes: { + name: { + control: 'select', + options: Object.keys(defaultIcons), + }, + }, + args: { + name: 'heart', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Primary: Story = { + args: { + name: 'heart', + }, +}; + +export const WithCustomIcon: Story = { + args: { + name: 'arrowDown', + }, + decorators: [ + Story => ( +
Custom Icon
}}> + +
+ ), + ], +}; diff --git a/packages/canon/src/components/Icon/Icon.tsx b/packages/canon/src/components/Icon/Icon.tsx new file mode 100644 index 0000000000..a45cd6f27e --- /dev/null +++ b/packages/canon/src/components/Icon/Icon.tsx @@ -0,0 +1,34 @@ +/* + * 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 React from 'react'; +import { useTheme } from '../../theme/context'; +import type { IconProps } from './types'; + +/** @public */ +export const Icon = (props: IconProps) => { + const { name, size = 16 } = props; + const { icons } = useTheme(); + + const RemixIcon = icons[name] as React.ComponentType<{ className?: string }>; + + if (!RemixIcon) { + console.error(`Icon "${name}" not found or is not a valid component.`); + return ; // Return a default icon or handle the error appropriately + } + + return ; +}; diff --git a/packages/canon/src/components/Icon/icons.ts b/packages/canon/src/components/Icon/icons.ts new file mode 100644 index 0000000000..ff5cd9a507 --- /dev/null +++ b/packages/canon/src/components/Icon/icons.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ + +// We can add custom icons to the list outside of Remix + +import type { IconMap } from './types'; +import { + RiHeartFill, + RiArrowDownFill, + RiCloudFill, + RiArrowLeftFill, + RiArrowRightFill, + RiArrowUpFill, + RiDeleteBin6Line, + RiAddLine, + RiArrowDownSLine, + RiArrowUpSLine, + RiArrowLeftSLine, + RiArrowRightSLine, + RiArrowDownCircleLine, + RiArrowLeftCircleLine, + RiArrowRightCircleLine, + RiArrowUpCircleLine, + RiCheckLine, +} from '@remixicon/react'; + +// List of default icons +export const defaultIcons: IconMap = { + arrowDown: RiArrowDownFill, + arrowLeft: RiArrowLeftFill, + arrowRight: RiArrowRightFill, + arrowUp: RiArrowUpFill, + arrowDownCircle: RiArrowDownCircleLine, + arrowLeftCircle: RiArrowLeftCircleLine, + arrowRightCircle: RiArrowRightCircleLine, + arrowUpCircle: RiArrowUpCircleLine, + check: RiCheckLine, + chevronDown: RiArrowDownSLine, + chevronUp: RiArrowUpSLine, + chevronLeft: RiArrowLeftSLine, + chevronRight: RiArrowRightSLine, + cloud: RiCloudFill, + heart: RiHeartFill, + plus: RiAddLine, + trash: RiDeleteBin6Line, +}; diff --git a/packages/canon/src/components/Icon/index.tsx b/packages/canon/src/components/Icon/index.tsx new file mode 100644 index 0000000000..3e7564c77e --- /dev/null +++ b/packages/canon/src/components/Icon/index.tsx @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export * from './Icon'; +export type * from './types'; diff --git a/packages/cli-node/src/paths.ts b/packages/canon/src/components/Icon/styles.css similarity index 75% rename from packages/cli-node/src/paths.ts rename to packages/canon/src/components/Icon/styles.css index 2c658c27b3..234105ed4e 100644 --- a/packages/cli-node/src/paths.ts +++ b/packages/canon/src/components/Icon/styles.css @@ -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,7 +14,17 @@ * limitations under the License. */ -import { findPaths } from '@backstage/cli-common'; +.icon-12 { + width: 12px; + height: 12px; +} -/* eslint-disable-next-line no-restricted-syntax */ -export const paths = findPaths(__dirname); +.icon-16 { + width: 16px; + height: 16px; +} + +.icon-24 { + width: 24px; + height: 24px; +} diff --git a/packages/canon/src/components/Icon/types.ts b/packages/canon/src/components/Icon/types.ts new file mode 100644 index 0000000000..a65a9f0913 --- /dev/null +++ b/packages/canon/src/components/Icon/types.ts @@ -0,0 +1,44 @@ +/* + * 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. + */ + +/** @public */ +export type IconNames = + | 'arrowDown' + | 'arrowLeft' + | 'arrowRight' + | 'arrowUp' + | 'arrowDownCircle' + | 'arrowLeftCircle' + | 'arrowRightCircle' + | 'arrowUpCircle' + | 'check' + | 'chevronDown' + | 'chevronLeft' + | 'chevronRight' + | 'chevronUp' + | 'cloud' + | 'heart' + | 'plus' + | 'trash'; + +/** @public */ +export type IconMap = Partial>; + +/** @public */ +export type IconProps = { + name: IconNames; + size?: number; +}; diff --git a/packages/canon/src/components/Inline/Docs.mdx b/packages/canon/src/components/Inline/Docs.mdx new file mode 100644 index 0000000000..8ff19747f0 --- /dev/null +++ b/packages/canon/src/components/Inline/Docs.mdx @@ -0,0 +1,125 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as InlineStories from './Inline.stories'; +import { Title, Text, PropsTable, getProps } from '../../../docs/components'; +import { spacingProperties } from '../../layout/sprinkles.css'; +import { inlineProperties } from './sprinkles.css'; + + + + + +Inline + + + The Inline component is used to create a horizontal layout of elements. By + default it uses flex and flexWrap to make sure that your content always flows + responsively. + + +Usage + + Hello World + Hello World + Hello World +
+`} language="tsx" dark /> + + + API reference + + + + + + The grid component also accepts all the spacing props from the Box component. + + + + +Examples + +Simple +A simple example of how to use the Inline component. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Responsive + + The Inline component also supports responsive values, making it easy to create + responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align + + The Inline component also supports responsive alignment, making it easy to + create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align vertically + + The Inline component also supports responsive vertical alignment, making it + easy to create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Inline/Inline.stories.tsx b/packages/canon/src/components/Inline/Inline.stories.tsx new file mode 100644 index 0000000000..613fd68c68 --- /dev/null +++ b/packages/canon/src/components/Inline/Inline.stories.tsx @@ -0,0 +1,128 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Inline } from './Inline'; +import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; + +const meta = { + title: 'Components/Inline', + component: Inline, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + align: { + control: 'inline-radio', + options: ['left', 'center', 'right'], + }, + alignY: { + control: 'inline-radio', + options: ['top', 'center', 'bottom'], + }, + children: { + control: false, + }, + as: { + control: false, + }, + className: { + control: 'text', + }, + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const FakeBox = ({ + width = 120, + height = 80, +}: { + width?: number; + height?: number; +}) => ( + +); + +export const Default: Story = { + args: { + children: ( + <> + {Array.from({ length: 32 }).map((_, index) => ( + + ))} + + ), + }, +}; + +export const AlignLeft: Story = { + args: { + ...Default.args, + align: 'left', + }, +}; + +export const AlignCenter: Story = { + args: { + ...Default.args, + align: 'center', + }, +}; + +export const AlignRight: Story = { + args: { + ...Default.args, + align: 'right', + }, +}; + +export const VerticalAlignTop: Story = { + args: { + ...Default.args, + alignY: 'top', + }, +}; + +export const VerticalAlignCenter: Story = { + args: { + ...Default.args, + alignY: 'center', + }, +}; + +export const VerticalAlignBottom: Story = { + args: { + ...Default.args, + alignY: 'bottom', + }, +}; + +export const LargeGap: Story = { + args: { + ...Default.args, + gap: 'xl', + }, +}; diff --git a/packages/canon/src/components/Inline/Inline.tsx b/packages/canon/src/components/Inline/Inline.tsx new file mode 100644 index 0000000000..b583b2ae08 --- /dev/null +++ b/packages/canon/src/components/Inline/Inline.tsx @@ -0,0 +1,67 @@ +/* + * 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 { createElement, forwardRef } from 'react'; +import { inlineSprinkles } from './sprinkles.css'; +import type { InlineProps } from './types'; + +const alignYToFlexAlign = (alignY: InlineProps['alignY']) => { + if (alignY === 'top') return 'flex-start'; + if (alignY === 'center') return 'center'; + if (alignY === 'bottom') return 'flex-end'; + return undefined; +}; + +const alignToFlexAlignY = (align: InlineProps['align']) => { + if (align === 'left') return 'flex-start'; + if (align === 'center') return 'center'; + if (align === 'right') return 'flex-end'; + return undefined; +}; + +/** @public */ +export const Inline = forwardRef((props, ref) => { + const { + as = 'div', + children, + align = 'left', + alignY = 'top', + gap = 'xs', + className, + style, + ...restProps + } = props; + + // Generate the list of class names + const sprinklesClassName = inlineSprinkles({ + ...restProps, + gap, + alignItems: alignYToFlexAlign(alignY), + justifyContent: alignToFlexAlignY(align), + }); + + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = ['inline', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement(as, { + ref, + className: classNames, + style, + children, + }); +}); diff --git a/packages/canon/src/components/Inline/index.ts b/packages/canon/src/components/Inline/index.ts new file mode 100644 index 0000000000..2cc100c02a --- /dev/null +++ b/packages/canon/src/components/Inline/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Inline } from './Inline'; +export type { InlineProps } from './types'; diff --git a/packages/canon/src/components/Inline/sprinkles.css.ts b/packages/canon/src/components/Inline/sprinkles.css.ts new file mode 100644 index 0000000000..ccd4126608 --- /dev/null +++ b/packages/canon/src/components/Inline/sprinkles.css.ts @@ -0,0 +1,34 @@ +/* + * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +export const inlineProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + alignItems: ['flex-start', 'center', 'flex-end'], + justifyContent: ['flex-start', 'center', 'flex-end'], + }, +}); + +export const inlineSprinkles = createSprinkles( + spacingProperties, + colorProperties, + inlineProperties, +); diff --git a/packages/canon/src/components/Inline/styles.css b/packages/canon/src/components/Inline/styles.css new file mode 100644 index 0000000000..fb9b1c3825 --- /dev/null +++ b/packages/canon/src/components/Inline/styles.css @@ -0,0 +1,4 @@ +.inline { + display: flex; + flex-wrap: wrap; +} diff --git a/packages/canon/src/components/Inline/types.ts b/packages/canon/src/components/Inline/types.ts new file mode 100644 index 0000000000..3d981d0d31 --- /dev/null +++ b/packages/canon/src/components/Inline/types.ts @@ -0,0 +1,36 @@ +/* + * 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 { AsProps, Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +/** @public */ +export interface InlineProps extends SpaceProps, ColorProps { + children: React.ReactNode; + as?: AsProps; + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + alignY?: + | 'top' + | 'center' + | 'bottom' + | Partial>; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Stack/Docs.mdx b/packages/canon/src/components/Stack/Docs.mdx new file mode 100644 index 0000000000..f1776e0262 --- /dev/null +++ b/packages/canon/src/components/Stack/Docs.mdx @@ -0,0 +1,126 @@ +import { Meta, Unstyled, Source } from '@storybook/blocks'; +import * as StackStories from './Stack.stories'; +import { Title, Text, PropsTable, getProps } from '../../../docs/components'; +import { spacingProperties } from '../../layout/sprinkles.css'; + + + + + +Stack + + + This is the stack 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. + + +Usage + + Hello World + Hello World + Hello World + +`} language="tsx" dark /> + + + API reference + + + + + + The grid component also accepts all the spacing props from the Box component. + + + + +Common questions + +Can I stack horizontally? + + The Stack component only allows for stacking elements vertically. If you want + to create a column layout, please use the Grid component. + + + + Hello World + Hello World + Hello World + +`} + language="tsx" + dark +/> + +Examples + +Simple + + A simple example of how to use the Stack component with a medium gap. + + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Responsive + + The Stack component also supports responsive values, making it easy to create + responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + +Align + + The Stack component also supports responsive alignment, making it easy to + create responsive designs. + + + Hello World + Hello World + Hello World +`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Stack/Stack.stories.tsx b/packages/canon/src/components/Stack/Stack.stories.tsx new file mode 100644 index 0000000000..331c2ee1e1 --- /dev/null +++ b/packages/canon/src/components/Stack/Stack.stories.tsx @@ -0,0 +1,123 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Stack } from './Stack'; +import { Box } from '../Box/Box'; +import { argTypesSpacing, argTypesColor } from '../../../docs/utils/argTypes'; + +const meta = { + title: 'Components/Stack', + component: Stack, + argTypes: { + ...argTypesSpacing, + ...argTypesColor, + align: { + control: 'inline-radio', + options: ['left', 'center', 'right'], + }, + children: { + control: false, + }, + as: { + control: false, + }, + className: { + control: 'text', + }, + }, + args: { + align: 'left', + gap: 'xs', + }, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +const FakeBox = () => ( + + Fake Box + +); + +export const Default: Story = { + args: { + children: ( + <> + + + + + ), + }, +}; + +export const AlignLeft: Story = { + args: { + ...Default.args, + align: 'left', + }, +}; + +export const AlignCenter: Story = { + args: { + ...Default.args, + align: 'center', + }, +}; + +export const AlignRight: Story = { + args: { + ...Default.args, + align: 'right', + }, +}; + +export const ResponsiveAlign: Story = { + args: { + ...Default.args, + align: { + xs: 'left', + md: 'center', + lg: 'right', + }, + }, +}; + +export const ResponsiveGap: Story = { + args: { + ...Default.args, + gap: { + xs: 'xs', + md: 'md', + lg: '2xl', + }, + }, +}; + +export const LargeGap: Story = { + args: { + ...Default.args, + gap: 'xl', + }, +}; diff --git a/packages/canon/src/components/Stack/Stack.tsx b/packages/canon/src/components/Stack/Stack.tsx new file mode 100644 index 0000000000..e0c36f2043 --- /dev/null +++ b/packages/canon/src/components/Stack/Stack.tsx @@ -0,0 +1,61 @@ +/* + * 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 { createElement, forwardRef } from 'react'; +import { StackProps } from './types'; +import { stackSprinkles } from './sprinkles.css'; + +const alignToFlexAlign = (align: StackProps['align']) => { + if (align === 'left') return 'stretch'; + if (align === 'center') return 'center'; + if (align === 'right') return 'flex-end'; + return undefined; +}; + +/** @public */ +export const Stack = forwardRef((props, ref) => { + const { + as = 'div', + children, + align = 'left', + gap = 'xs', + className, + style, + ...restProps + } = props; + + // Transform the align prop + const flexAlign = alignToFlexAlign(align); + + // Generate the list of class names + const sprinklesClassName = stackSprinkles({ + ...restProps, + gap, + alignItems: flexAlign, + }); + + // Combine the base class name, the sprinkles class name, and any additional class names + const classNames = ['stack', sprinklesClassName, className] + .filter(Boolean) + .join(' '); + + return createElement(as, { + ref, + className: classNames, + style, + children, + }); +}); diff --git a/packages/canon/src/components/Stack/index.ts b/packages/canon/src/components/Stack/index.ts new file mode 100644 index 0000000000..7abbc3f439 --- /dev/null +++ b/packages/canon/src/components/Stack/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ +export { Stack } from './Stack'; +export type { StackProps } from './types'; diff --git a/packages/canon/src/components/Stack/sprinkles.css.ts b/packages/canon/src/components/Stack/sprinkles.css.ts new file mode 100644 index 0000000000..85c8f83a71 --- /dev/null +++ b/packages/canon/src/components/Stack/sprinkles.css.ts @@ -0,0 +1,33 @@ +/* + * 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 { defineProperties, createSprinkles } from '@vanilla-extract/sprinkles'; +import { breakpoints } from '../../layout/properties'; +import { colorProperties, spacingProperties } from '../../layout/sprinkles.css'; + +const stackProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + properties: { + alignItems: ['stretch', 'flex-start', 'center', 'flex-end'], + }, +}); + +export const stackSprinkles = createSprinkles( + spacingProperties, + colorProperties, + stackProperties, +); diff --git a/packages/canon/src/components/Stack/styles.css b/packages/canon/src/components/Stack/styles.css new file mode 100644 index 0000000000..784fd3b1ab --- /dev/null +++ b/packages/canon/src/components/Stack/styles.css @@ -0,0 +1,4 @@ +.stack { + display: flex; + flex-direction: column; +} diff --git a/packages/canon/src/components/Stack/types.ts b/packages/canon/src/components/Stack/types.ts new file mode 100644 index 0000000000..529e92d1bd --- /dev/null +++ b/packages/canon/src/components/Stack/types.ts @@ -0,0 +1,30 @@ +/* + * 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 { AsProps, Breakpoint, ColorProps } from '../../layout/types'; +import { SpaceProps } from '../../layout/types'; + +/** @public */ +export interface StackProps extends SpaceProps, ColorProps { + children: React.ReactNode; + as?: AsProps; + align?: + | 'left' + | 'center' + | 'right' + | Partial>; + className?: string; + style?: React.CSSProperties; +} diff --git a/packages/canon/src/components/Table/Docs.mdx b/packages/canon/src/components/Table/Docs.mdx new file mode 100644 index 0000000000..6a6e9c8a59 --- /dev/null +++ b/packages/canon/src/components/Table/Docs.mdx @@ -0,0 +1,5 @@ +import { Meta, Controls } from '@storybook/blocks'; + + + +# Table diff --git a/packages/canon/src/components/Table/Table.tsx b/packages/canon/src/components/Table/Table.tsx new file mode 100644 index 0000000000..efd5181036 --- /dev/null +++ b/packages/canon/src/components/Table/Table.tsx @@ -0,0 +1,115 @@ +/* + * 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 * as React from 'react'; + +/** @public */ +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)); +Table.displayName = 'Table'; + +/** @public */ +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableHeader.displayName = 'TableHeader'; + +/** @public */ +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableBody.displayName = 'TableBody'; + +/** @public */ +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableFooter.displayName = 'TableFooter'; + +/** @public */ +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + + {props.children} + +)); +TableRow.displayName = 'TableRow'; + +/** @public */ +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableHead.displayName = 'TableHead'; + +/** @public */ +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableCell.displayName = 'TableCell'; + +/** @public */ +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableCaption.displayName = 'TableCaption'; + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}; diff --git a/packages/canon/src/components/Table/index.ts b/packages/canon/src/components/Table/index.ts new file mode 100644 index 0000000000..cf88de2b1a --- /dev/null +++ b/packages/canon/src/components/Table/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +export { + Table, + TableHead, + TableRow, + TableHeader, + TableCell, + TableBody, + TableFooter, +} from './Table'; diff --git a/packages/canon/src/components/Table/stories/Example1.stories.tsx b/packages/canon/src/components/Table/stories/Example1.stories.tsx new file mode 100644 index 0000000000..140293438e --- /dev/null +++ b/packages/canon/src/components/Table/stories/Example1.stories.tsx @@ -0,0 +1,111 @@ +/* + * 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 * as React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { + Table, + TableHead, + TableRow, + TableHeader, + TableCell, + TableBody, + TableFooter, +} from '../Table'; + +const meta = { + title: 'Components/Table/Examples/Simple', + component: Table, +} satisfies Meta; + +const invoices = [ + { + invoice: 'INV001', + paymentStatus: 'Paid', + totalAmount: '$250.00', + paymentMethod: 'Credit Card', + }, + { + invoice: 'INV002', + paymentStatus: 'Pending', + totalAmount: '$150.00', + paymentMethod: 'PayPal', + }, + { + invoice: 'INV003', + paymentStatus: 'Unpaid', + totalAmount: '$350.00', + paymentMethod: 'Bank Transfer', + }, + { + invoice: 'INV004', + paymentStatus: 'Paid', + totalAmount: '$450.00', + paymentMethod: 'Credit Card', + }, + { + invoice: 'INV005', + paymentStatus: 'Paid', + totalAmount: '$550.00', + paymentMethod: 'PayPal', + }, + { + invoice: 'INV006', + paymentStatus: 'Pending', + totalAmount: '$200.00', + paymentMethod: 'Bank Transfer', + }, + { + invoice: 'INV007', + paymentStatus: 'Unpaid', + totalAmount: '$300.00', + paymentMethod: 'Credit Card', + }, +]; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => ( + + + + Invoice + Status + Method + Amount + + + + {invoices.map(invoice => ( + + {invoice.invoice} + {invoice.paymentStatus} + {invoice.paymentMethod} + {invoice.totalAmount} + + ))} + + + + Total + $2,500.00 + + +
+ ), +}; diff --git a/packages/canon/src/components/Table/stories/Table.stories.tsx b/packages/canon/src/components/Table/stories/Table.stories.tsx new file mode 100644 index 0000000000..2267b77093 --- /dev/null +++ b/packages/canon/src/components/Table/stories/Table.stories.tsx @@ -0,0 +1,32 @@ +/* + * 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 { Table } from '../Table'; + +const meta = { + title: 'Components/Table/Components/Table', + component: Table, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Hello World! I'm a basic table", + }, +}; diff --git a/packages/canon/src/components/Table/stories/TableBody.stories.tsx b/packages/canon/src/components/Table/stories/TableBody.stories.tsx new file mode 100644 index 0000000000..f69d26f0bd --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableBody.stories.tsx @@ -0,0 +1,40 @@ +/* + * 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 * as React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Table, TableBody } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableBody', + component: TableBody, + decorators: [ + Story => ( + + +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Hello World! I'm a basic table body", + }, +}; diff --git a/packages/canon/src/components/Table/stories/TableCaption.stories.tsx b/packages/canon/src/components/Table/stories/TableCaption.stories.tsx new file mode 100644 index 0000000000..46ea5f0f4d --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableCaption.stories.tsx @@ -0,0 +1,30 @@ +/* + * 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 { TableCaption } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableCaption', + component: TableCaption, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableCell.stories.tsx b/packages/canon/src/components/Table/stories/TableCell.stories.tsx new file mode 100644 index 0000000000..126b72bf95 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableCell.stories.tsx @@ -0,0 +1,30 @@ +/* + * 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 { TableCell } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableCell', + component: TableCell, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableFooter.stories.tsx b/packages/canon/src/components/Table/stories/TableFooter.stories.tsx new file mode 100644 index 0000000000..b7dbacbc30 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableFooter.stories.tsx @@ -0,0 +1,30 @@ +/* + * 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 { TableFooter } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableFooter', + component: TableFooter, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableHead.stories.tsx b/packages/canon/src/components/Table/stories/TableHead.stories.tsx new file mode 100644 index 0000000000..c7cfac51e8 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableHead.stories.tsx @@ -0,0 +1,30 @@ +/* + * 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 { TableHead } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableHead', + component: TableHead, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/packages/canon/src/components/Table/stories/TableHeader.stories.tsx b/packages/canon/src/components/Table/stories/TableHeader.stories.tsx new file mode 100644 index 0000000000..a2f044dcc3 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableHeader.stories.tsx @@ -0,0 +1,40 @@ +/* + * 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 * as React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Table, TableHeader } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableHeader', + component: TableHeader, + decorators: [ + Story => ( + + +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Hello World! I'm a basic table header", + }, +}; diff --git a/packages/canon/src/components/Table/stories/TableRow.stories.tsx b/packages/canon/src/components/Table/stories/TableRow.stories.tsx new file mode 100644 index 0000000000..7eb58ed5a4 --- /dev/null +++ b/packages/canon/src/components/Table/stories/TableRow.stories.tsx @@ -0,0 +1,42 @@ +/* + * 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 * as React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Table, TableRow, TableHeader } from '../Table'; + +const meta = { + title: 'Components/Table/Components/TableRow', + component: TableRow, + decorators: [ + Story => ( + + + + +
+ ), + ], +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: "Hello World! I'm a basic table row", + }, +}; diff --git a/packages/canon/src/components/Table/styles.css b/packages/canon/src/components/Table/styles.css new file mode 100644 index 0000000000..bf3d8603e3 --- /dev/null +++ b/packages/canon/src/components/Table/styles.css @@ -0,0 +1,65 @@ +.table { + position: relative; + overflow: auto; + width: 100%; + background-color: var(--canon-surface-1); + border-radius: var(--canon-border-radius-xs); + padding-bottom: var(--canon-spacing-5xs); + padding-top: var(--canon-spacing-5xs); + font-size: var(--canon-font-size-body); + + table { + width: 100%; + caption-side: bottom; + font-size: var(--canon-font-size-sm); + border-collapse: collapse; + } +} + +.table-header { + tr { + /* border-bottom: 1px solid var(--canon-outline); */ + } +} + +.table-head { + text-align: left; + padding: var(--canon-spacing-xs); +} + +.table-body { + tr:last-child { + border-bottom: none; + } +} + +.table-row { + transition: color 0.2s ease-in-out; + + &:hover td { + background-color: var(--canon-surface-3); + } + + & .table-cell:first-child { + border-top-left-radius: var(--canon-border-radius-xs); + border-bottom-left-radius: var(--canon-border-radius-xs); + box-shadow: inset 4px 2px 0 0 var(--canon-surface-1), + inset 4px -2px 0 0 var(--canon-surface-1); + padding-left: var(--canon-spacing-xs); + } + + & .table-cell:last-child { + border-top-right-radius: var(--canon-border-radius-xs); + border-bottom-right-radius: var(--canon-border-radius-xs); + box-shadow: inset -4px 2px 0 0 var(--canon-surface-1), + inset -4px -2px 0 0 var(--canon-surface-1); + padding-right: var(--canon-spacing-xs); + } +} + +.table-cell { + padding: var(--canon-spacing-xs); + background-color: var(--canon-surface-2); + box-shadow: inset 0px 2px 0 0 var(--canon-surface-1), + inset 0px -2px 0 0 var(--canon-surface-1); +} diff --git a/packages/canon/src/components/Text/Docs.mdx b/packages/canon/src/components/Text/Docs.mdx new file mode 100644 index 0000000000..685a00a33f --- /dev/null +++ b/packages/canon/src/components/Text/Docs.mdx @@ -0,0 +1,101 @@ +import { Canvas, Meta, Unstyled, Source } from '@storybook/blocks'; +import * as TextStories from './Text.stories'; +import { Title, Text } from '../../../docs/components'; +import { PropsTable } from '../../../docs/components/PropsTable/PropsTable'; + + + + + +Text + +The `Text` component is used to display content on your page. + + + +Usage +Hello World!`} language="tsx" dark /> + + + API reference + + + + +Examples +Here are some examples of how you can use the Text component. + +All variants + + The `Text` component has a `variant` prop that can be used to change the + appearance of the text. + + + + + + Subtitle Lorem ipsum dolor sit amet consectetur... + Body Lorem ipsum dolor sit amet consectetur... + Caption Lorem ipsum dolor sit amet consectetur... + Label Lorem ipsum dolor sit amet consectetur... +`} + language="tsx" + dark +/> + +All weights + + The `Text` component has a `weight` prop that can be used to change the + appearance of the text. + + + + + + Regular Lorem ipsum dolor sit amet consectetur... + Bold Lorem ipsum dolor sit amet consectetur... +`} + language="tsx" + dark +/> + +Responsive + + You can also use the `variant` prop to change the appearance of the text based + on the screen size. + + +Responsive Lorem ipsum dolor sit amet consectetur...`} + language="tsx" + dark +/> + + diff --git a/packages/canon/src/components/Text/Text.stories.tsx b/packages/canon/src/components/Text/Text.stories.tsx new file mode 100644 index 0000000000..2cde7ed553 --- /dev/null +++ b/packages/canon/src/components/Text/Text.stories.tsx @@ -0,0 +1,71 @@ +/* + * 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 React from 'react'; +import type { Meta, StoryObj } from '@storybook/react'; +import { Text } from './Text'; +import { Stack } from '../Stack'; + +const meta = { + title: 'Components/Text', + component: Text, +} satisfies Meta; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + children: + 'Lorem ipsum dolor sit amet consectetur. Nec arcu vel lacus magna adipiscing nisi mauris tortor viverra. Enim rhoncus quisque consectetur ligula diam ac lacus massa. Id interdum id pellentesque justo ut massa nibh amet. Odio massa in scelerisque tortor massa integer purus amet enim. Eros sit neque nullam facilisis. Purus massa dignissim aliquet purus eu in. Urna consequat ullamcorper arcu amet dictumst. Commodo praesent turpis fringilla tristique congue volutpat in. Nulla in nulla ultrices lacus. In ultrices id tellus ut.', + }, +}; + +export const AllVariants: Story = { + args: { + children: 'Text', + }, + render: () => ( + + Subtitle {Default.args?.children} + Body {Default.args?.children} + Caption {Default.args?.children} + Label {Default.args?.children} + + ), +}; + +export const AllWeights: Story = { + args: { + children: 'Text', + }, + render: () => ( + + Regular {Default.args?.children} + Bold {Default.args?.children} + + ), +}; + +export const Responsive: Story = { + args: { + ...Default.args, + variant: { + xs: 'label', + md: 'body', + }, + }, +}; diff --git a/packages/canon/src/components/Text/Text.tsx b/packages/canon/src/components/Text/Text.tsx new file mode 100644 index 0000000000..1c718786fa --- /dev/null +++ b/packages/canon/src/components/Text/Text.tsx @@ -0,0 +1,50 @@ +/* + * 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 React, { forwardRef } from 'react'; +import { TextProps } from './types'; +import { useTheme } from '../../theme/context'; +import { getResponsiveValue } from '../../utils/getResponsiveValue'; + +export const Text = forwardRef( + (props, ref) => { + const { + children, + variant = 'body', + weight = 'regular', + ...restProps + } = props; + + const { breakpoint } = useTheme(); + + const responsiveVariant = getResponsiveValue(variant, breakpoint); + const responsiveWeight = getResponsiveValue(weight, breakpoint); + + return ( +

+ {children} +

+ ); + }, +); + +Text.displayName = 'Text'; diff --git a/packages/canon/src/components/Text/index.ts b/packages/canon/src/components/Text/index.ts new file mode 100644 index 0000000000..ae1f532b2c --- /dev/null +++ b/packages/canon/src/components/Text/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { Text } from './Text'; +export type { TextProps } from './types'; diff --git a/packages/canon/src/components/Text/styles.css b/packages/canon/src/components/Text/styles.css new file mode 100644 index 0000000000..9bf22ccab5 --- /dev/null +++ b/packages/canon/src/components/Text/styles.css @@ -0,0 +1,50 @@ +/* + * 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. + */ + +.text { + font-family: var(--canon-font-regular); + color: var(--canon-text-primary); + padding: 0; + margin: 0; + + &.text-body { + font-size: var(--canon-font-size-body); + line-height: 140%; + } + + &.text-subtitle { + font-size: var(--canon-font-size-subtitle); + line-height: 140%; + } + + &.text-caption { + font-size: var(--canon-font-size-caption); + line-height: 140%; + } + + &.text-label { + font-size: var(--canon-font-size-label); + line-height: 140%; + } + + &.text-regular { + font-weight: var(--canon-font-weight-regular); + } + + &.text-bold { + font-weight: var(--canon-font-weight-bold); + } +} diff --git a/packages/canon/src/components/Text/types.ts b/packages/canon/src/components/Text/types.ts new file mode 100644 index 0000000000..b054fdf2cf --- /dev/null +++ b/packages/canon/src/components/Text/types.ts @@ -0,0 +1,29 @@ +/* + * 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 { Breakpoint } from '../../layout/types'; + +/** @public */ +export interface TextProps { + children: React.ReactNode; + variant?: + | 'subtitle' + | 'body' + | 'caption' + | 'label' + | Partial>; + weight?: 'regular' | 'bold' | Partial>; +} diff --git a/packages/canon/src/css/components.css b/packages/canon/src/css/components.css new file mode 100644 index 0000000000..ed602b7ab7 --- /dev/null +++ b/packages/canon/src/css/components.css @@ -0,0 +1,27 @@ +/* + * 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. + */ + +/* Components */ +@import '../components/Button/styles.css'; +@import '../components/Stack/styles.css'; +@import '../components/Inline/styles.css'; +@import '../components/Grid/styles.css'; +@import '../components/Container/styles.css'; +@import '../components/Icon/styles.css'; +@import '../components/Checkbox/styles.css'; +@import '../components/Table/styles.css'; +@import '../components/Text/styles.css'; +@import '../components/Heading/styles.css'; diff --git a/packages/canon/src/css/core.css b/packages/canon/src/css/core.css new file mode 100644 index 0000000000..eec5b26836 --- /dev/null +++ b/packages/canon/src/css/core.css @@ -0,0 +1,122 @@ +/* + * 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. + */ + +/* Normalize */ +@import './normalize.css'; + +*, +html, +body { + font-family: var(--canon-font-regular); +} + +/* Light theme tokens */ +:root { + /* Colors */ + --canon-accent: #000; + --canon-background: #f8f8f8; + --canon-surface-1: #fff; + --canon-surface-2: #f4f4f4; + --canon-surface-3: #f1f1f1; + + /* Outlines */ + --canon-outline: rgba(0, 0, 0, 0.1); + --canon-outline-hover: rgba(0, 0, 0, 0.2); + --canon-outline-focus: #000; + + /* States - Add more states */ + --canon-error: #f50000; + + /* Text colors */ + --canon-text-primary: #000; + --canon-text-primary-on-accent: #fff; + --canon-text-secondary: #646464; + + /* Box shadows */ + --canon-box-shadow-small: 0 0 0 1px rgba(0, 0, 0, 0.05); + --canon-box-shadow-medium: 0 0 0 1px rgba(0, 0, 0, 0.1); + --canon-box-shadow-large: 0 0 0 1px rgba(0, 0, 0, 0.2); + + /* Font families */ + --canon-font-regular: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; + --canon-font-monospace: 'Monospace', monospace; + + /* Font weights */ + --canon-font-weight-regular: 400; + --canon-font-weight-bold: 600; + + /* Font sizes */ + --canon-font-size-label: 0.625rem; /* 10px */ + --canon-font-size-caption: 0.75rem; /* 12px */ + --canon-font-size-body: 0.875rem; /* 14px */ + --canon-font-size-subtitle: 1rem; /* 16px */ + --canon-font-size-title5: 1.25rem; /* 20px */ + --canon-font-size-title4: 1.5rem; /* 24px */ + --canon-font-size-title3: 2rem; /* 32px */ + --canon-font-size-title2: 3rem; /* 48px */ + --canon-font-size-title1: 4rem; /* 64px */ + --canon-font-size-display: 5.75rem; /* 92px */ + + /* Spacing */ + --canon-spacing-5xs: 0.125rem; /* 2px */ + --canon-spacing-4xs: 0.25rem; /* 4px */ + --canon-spacing-3xs: 0.375rem; /* 6px */ + --canon-spacing-2xs: 0.5rem; /* 8px */ + --canon-spacing-xs: 0.75rem; /* 12px */ + --canon-spacing-sm: 1rem; /* 16px */ + --canon-spacing-md: 1.5rem; /* 24px */ + --canon-spacing-lg: 2rem; /* 32px */ + --canon-spacing-xl: 2.5rem; /* 40px */ + --canon-spacing-2xl: 3rem; /* 48px */ + --canon-spacing-3xl: 3.5rem; /* 56px */ + + /* Border radius */ + --canon-border-radius-2xs: 0.125rem; /* 2px */ + --canon-border-radius-xs: 0.25rem; /* 4px */ + --canon-border-radius-sm: 0.5rem; /* 8px */ + --canon-border-radius-md: 0.75rem; /* 12px */ + --canon-border-radius-lg: 1rem; /* 16px */ + --canon-border-radius-xl: 1.25rem; /* 20px */ + --canon-border-radius-2xl: 1.5rem; /* 24px */ + + /* Container */ + --canon-container-max-width: 1200px; + --canon-container-padding: 1rem; +} + +/* Dark theme tokens */ +[data-theme='dark'] { + /* Colors */ + --canon-accent: #fff; + --canon-background: #000; + --canon-surface-1: #121212; + --canon-surface-2: #1a1a1a; + + /* Outlines */ + --canon-outline: rgba(255, 255, 255, 0.2); + --canon-outline-hover: rgba(255, 255, 255, 0.4); + --canon-outline-focus: #fff; + + /* States - Add more states */ + --canon-error: #f50000; + + /* Text colors */ + --canon-text-primary: #fff; + --canon-text-primary-on-accent: #000; + --canon-text-secondary: #b3b3b3; +} diff --git a/packages/canon/src/css/normalize.css b/packages/canon/src/css/normalize.css new file mode 100644 index 0000000000..80e1ca4119 --- /dev/null +++ b/packages/canon/src/css/normalize.css @@ -0,0 +1,201 @@ +/*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize */ + +/* +Document +======== +*/ + +/** +Use a better box model (opinionated). +*/ + +*, +::before, +::after { + box-sizing: border-box; +} + +html { + /* Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) */ + font-family: system-ui, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji'; + line-height: 1.15; /* 1. Correct the line height in all browsers. */ + -webkit-text-size-adjust: 100%; /* 2. Prevent adjustments of font size after orientation changes in iOS. */ + tab-size: 4; /* 3. Use a more readable tab size (opinionated). */ +} + +/* +Sections +======== +*/ + +body { + margin: 0; /* Remove the margin in all browsers. */ +} + +/* +Text-level semantics +==================== +*/ + +/** +Add the correct font weight in Chrome and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/** +1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) +2. Correct the odd 'em' font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, + monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/** +Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +Tabular data +============ +*/ + +/** +Correct table border color inheritance in Chrome and Safari. (https://issues.chromium.org/issues/40615503, https://bugs.webkit.org/show_bug.cgi?id=195016) +*/ + +table { + border-color: currentcolor; +} + +/* +Forms +===== +*/ + +/** +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** +Correct the inability to style clickable types in iOS and Safari. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; +} + +/** +Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. +*/ + +legend { + padding: 0; +} + +/** +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/** +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/** +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to 'inherit' in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* +Interactive +=========== +*/ + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} diff --git a/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts b/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts new file mode 100644 index 0000000000..25ea45124e --- /dev/null +++ b/packages/canon/src/hooks/useIsomorphicLayoutEffect.ts @@ -0,0 +1,19 @@ +/* + * 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 { useEffect, useLayoutEffect } from 'react'; + +export const useIsomorphicLayoutEffect = + typeof window !== 'undefined' ? useLayoutEffect : useEffect; diff --git a/packages/canon/src/hooks/useMediaQuery.ts b/packages/canon/src/hooks/useMediaQuery.ts new file mode 100644 index 0000000000..9e2cc9ef0b --- /dev/null +++ b/packages/canon/src/hooks/useMediaQuery.ts @@ -0,0 +1,76 @@ +/* + * 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 { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect'; + +type UseMediaQueryOptions = { + defaultValue?: boolean; + initializeWithValue?: boolean; +}; + +const IS_SERVER = typeof window === 'undefined'; + +export function useMediaQuery( + query: string, + { + defaultValue = false, + initializeWithValue = true, + }: UseMediaQueryOptions = {}, +): boolean { + const getMatches = (query: string): boolean => { + if (IS_SERVER) { + return defaultValue; + } + return window.matchMedia(query).matches; + }; + + const [matches, setMatches] = useState(() => { + if (initializeWithValue) { + return getMatches(query); + } + return defaultValue; + }); + + // Handles the change event of the media query. + function handleChange() { + setMatches(getMatches(query)); + } + + useIsomorphicLayoutEffect(() => { + const matchMedia = window.matchMedia(query); + + // Triggered at the first client-side load and if query changes + handleChange(); + + // Use deprecated `addListener` and `removeListener` to support Safari < 14 (#135) + if (matchMedia.addListener) { + matchMedia.addListener(handleChange); + } else { + matchMedia.addEventListener('change', handleChange); + } + + return () => { + if (matchMedia.removeListener) { + matchMedia.removeListener(handleChange); + } else { + matchMedia.removeEventListener('change', handleChange); + } + }; + }, [query]); + + return matches; +} diff --git a/packages/canon/src/index.ts b/packages/canon/src/index.ts new file mode 100644 index 0000000000..d6a375b8dd --- /dev/null +++ b/packages/canon/src/index.ts @@ -0,0 +1,37 @@ +/* + * 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. + */ + +/** + * Components used by Backstage plugins and apps + * + * @packageDocumentation + */ + +// Layout types +export * from './layout/types'; + +// Layout components +export * from './components/Box'; +export * from './components/Grid'; +export * from './components/Stack'; +export * from './components/Inline'; +export * from './components/Container'; + +// UI components +export * from './components/Button'; +export * from './components/Icon'; +export * from './components/Checkbox'; +export * from './components/Table'; diff --git a/packages/canon/src/layout/properties.ts b/packages/canon/src/layout/properties.ts new file mode 100644 index 0000000000..d41bbddbeb --- /dev/null +++ b/packages/canon/src/layout/properties.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +/** @public */ +export const breakpoints = { + xs: {}, + sm: { '@media': 'screen and (min-width: 640px)' }, + md: { '@media': 'screen and (min-width: 768px)' }, + lg: { '@media': 'screen and (min-width: 1024px)' }, + xl: { '@media': 'screen and (min-width: 1280px)' }, + '2xl': { '@media': 'screen and (min-width: 1536px)' }, +}; + +/** @public */ +export const themes = { + light: { selector: '[data-theme="light"] &' }, + dark: { selector: '[data-theme="dark"] &' }, +}; + +/** @public */ +export const space = { + none: 0, + '2xs': 'var(--canon-spacing-2xs)', + xs: 'var(--canon-spacing-xs)', + sm: 'var(--canon-spacing-sm)', + md: 'var(--canon-spacing-md)', + lg: 'var(--canon-spacing-lg)', + xl: 'var(--canon-spacing-xl)', + '2xl': 'var(--canon-spacing-2xl)', +}; diff --git a/packages/canon/src/layout/sprinkles.css.ts b/packages/canon/src/layout/sprinkles.css.ts new file mode 100644 index 0000000000..7e85487fe3 --- /dev/null +++ b/packages/canon/src/layout/sprinkles.css.ts @@ -0,0 +1,63 @@ +/* + * 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 { defineProperties } from '@vanilla-extract/sprinkles'; +import { breakpoints, space } from './properties'; + +export const spacingProperties = defineProperties({ + conditions: breakpoints, + defaultCondition: 'xs', + responsiveArray: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'], + properties: { + paddingTop: space, + paddingBottom: space, + paddingLeft: space, + paddingRight: space, + marginTop: space, + marginBottom: space, + marginLeft: space, + marginRight: space, + gap: space, + }, + shorthands: { + padding: ['paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight'], + paddingX: ['paddingLeft', 'paddingRight'], + paddingY: ['paddingTop', 'paddingBottom'], + margin: ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'], + marginX: ['marginLeft', 'marginRight'], + marginY: ['marginTop', 'marginBottom'], + }, +}); + +export const colorProperties = defineProperties({ + conditions: { + light: { selector: '[data-theme="light"] &' }, + dark: { selector: '[data-theme="dark"] &' }, + }, + defaultCondition: ['light', 'dark'], + properties: { + color: { + primary: 'var(--canon-text-primary)', + secondary: 'var(--canon-text-secondary)', + error: 'var(--canon-error)', + }, + background: { + background: 'var(--canon-background)', + elevation1: 'var(--canon-surface-1)', + elevation2: 'var(--canon-surface-2)', + transparent: 'transparent', + }, + }, +}); diff --git a/packages/canon/src/layout/types.ts b/packages/canon/src/layout/types.ts new file mode 100644 index 0000000000..c051dacb44 --- /dev/null +++ b/packages/canon/src/layout/types.ts @@ -0,0 +1,131 @@ +/* + * 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 { breakpoints, space, themes } from './properties'; + +/** @public */ +export type Breakpoint = keyof typeof breakpoints; + +/** @public */ +export type Space = keyof typeof space; + +/** @public */ +export type Theme = keyof typeof themes; + +/** @public */ +export type Gap = Space | Partial>; + +/** @public */ +export type PaddingLeft = Space | Partial>; + +/** @public */ +export type PaddingRight = Space | Partial>; + +/** @public */ +export type PaddingTop = Space | Partial>; + +/** @public */ +export type PaddingBottom = Space | Partial>; + +/** @public */ +export type Padding = Space | Partial>; + +/** @public */ +export type PaddingX = Space | Partial>; + +/** @public */ +export type PaddingY = Space | Partial>; + +/** @public */ +export type MarginLeft = Space | Partial>; + +/** @public */ +export type MarginRight = Space | Partial>; + +/** @public */ +export type MarginTop = Space | Partial>; + +/** @public */ +export type MarginBottom = Space | Partial>; + +/** @public */ +export type Margin = Space | Partial>; + +/** @public */ +export type MarginX = Space | Partial>; + +/** @public */ +export type MarginY = Space | Partial>; + +/** @public */ +export interface SpaceProps { + gap?: Gap; + padding?: Padding; + paddingLeft?: PaddingLeft; + paddingRight?: PaddingRight; + paddingTop?: PaddingTop; + paddingBottom?: PaddingBottom; + paddingX?: PaddingX; + paddingY?: PaddingY; + margin?: Margin; + marginLeft?: MarginLeft; + marginRight?: MarginRight; + marginTop?: MarginTop; + marginBottom?: MarginBottom; + marginX?: MarginX; + marginY?: MarginY; +} + +/** @public */ +export type Background = + | 'background' + | 'elevation1' + | 'elevation2' + | 'transparent' + | Partial< + Record + >; + +/** @public */ +export type Color = + | 'primary' + | 'secondary' + | 'error' + | Partial>; + +/** @public */ +export type AsProps = + | 'div' + | 'span' + | 'p' + | 'article' + | 'section' + | 'main' + | 'nav' + | 'aside' + | 'ul' + | 'ol' + | 'li' + | 'details' + | 'summary' + | 'dd' + | 'dl' + | 'dt'; + +/** @public */ +export interface ColorProps { + color?: Color; + background?: Background; +} diff --git a/packages/canon/src/theme/context.tsx b/packages/canon/src/theme/context.tsx new file mode 100644 index 0000000000..196c8fbb48 --- /dev/null +++ b/packages/canon/src/theme/context.tsx @@ -0,0 +1,79 @@ +/* + * 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 React, { createContext, useContext, ReactNode } from 'react'; +import { IconMap, IconNames } from '../components/Icon/types'; +import { defaultIcons } from '../components/Icon/icons'; +import { useMediaQuery } from '../hooks/useMediaQuery'; +import { Breakpoints } from '../types'; + +const defaultBreakpoints: Breakpoints = { + xs: '0px', + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', +}; + +interface ThemeContextProps { + icons: IconMap; + breakpoint: keyof Breakpoints; +} + +const ThemeContext = createContext({ + icons: defaultIcons, + breakpoint: 'md', +}); + +interface ThemeProviderProps { + children?: ReactNode; + overrides?: Partial>; + breakpoints?: Partial; +} + +/** @public */ +export const ThemeProvider = (props: ThemeProviderProps) => { + const { children, overrides, breakpoints = defaultBreakpoints } = props; + + // Merge provided overrides with default icons + const combinedIcons = { ...defaultIcons, ...overrides }; + + const isBreakpointSm = useMediaQuery(`(min-width: ${breakpoints.sm})`); + const isBreakpointMd = useMediaQuery(`(min-width: ${breakpoints.md})`); + const isBreakpointLg = useMediaQuery(`(min-width: ${breakpoints.lg})`); + const isBreakpointXl = useMediaQuery(`(min-width: ${breakpoints.xl})`); + const isBreakpoint2xl = useMediaQuery(`(min-width: ${breakpoints['2xl']})`); + + // Determine the current breakpoint + const breakpoint = (() => { + if (isBreakpoint2xl) return '2xl'; + if (isBreakpointXl) return 'xl'; + if (isBreakpointLg) return 'lg'; + if (isBreakpointMd) return 'md'; + if (isBreakpointSm) return 'sm'; + return 'xs'; + })(); + + return ( + + {children} + + ); +}; + +/** @public */ +export const useTheme = () => useContext(ThemeContext); diff --git a/packages/canon/src/types.ts b/packages/canon/src/types.ts new file mode 100644 index 0000000000..236d633f84 --- /dev/null +++ b/packages/canon/src/types.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ +export interface Breakpoints { + xs: string; + sm: string; + md: string; + lg: string; + xl: string; + '2xl': string; +} diff --git a/packages/canon/src/utils/getResponsiveValue.ts b/packages/canon/src/utils/getResponsiveValue.ts new file mode 100644 index 0000000000..858d0c8bcb --- /dev/null +++ b/packages/canon/src/utils/getResponsiveValue.ts @@ -0,0 +1,41 @@ +/* + * 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 { Breakpoints } from '../types'; + +export const getResponsiveValue = ( + value: any, + breakpoint: keyof Breakpoints, +) => { + if (typeof value === 'object') { + const breakpointsOrder: (keyof Breakpoints)[] = [ + 'xs', + 'sm', + 'md', + 'lg', + 'xl', + '2xl', + ]; + const index = breakpointsOrder.indexOf(breakpoint); + + for (let i = index; i >= 0; i--) { + if (value[breakpointsOrder[i]]) { + return value[breakpointsOrder[i]]; + } + } + return value['xs']; + } + return value; +}; diff --git a/packages/canon/static/CNAME b/packages/canon/static/CNAME new file mode 100644 index 0000000000..a07d95935a --- /dev/null +++ b/packages/canon/static/CNAME @@ -0,0 +1 @@ +canon.backstage.io diff --git a/packages/canon/static/favicon.svg b/packages/canon/static/favicon.svg new file mode 100644 index 0000000000..12cad81e95 --- /dev/null +++ b/packages/canon/static/favicon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/canon/static/header.png b/packages/canon/static/header.png new file mode 100644 index 0000000000..507bd05ca7 Binary files /dev/null and b/packages/canon/static/header.png differ diff --git a/packages/canon/static/logo.svg b/packages/canon/static/logo.svg new file mode 100644 index 0000000000..eb2b8aeaf2 --- /dev/null +++ b/packages/canon/static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/catalog-client/CHANGELOG.md b/packages/catalog-client/CHANGELOG.md index 3326f2a5f7..e9e525a0e1 100644 --- a/packages/catalog-client/CHANGELOG.md +++ b/packages/catalog-client/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/catalog-client +## 1.9.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + +## 1.9.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 1.8.1-next.0 + +### Patch Changes + +- d7e7836: Fixed a bug in the `queryEntities` method where errors were not being handled properly. +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 1.8.0 + +### Minor Changes + +- 656d1ef: Internal update to use the updated generated code from `backstage-cli package schema openapi generate --client-package ...`. +- 31c4fe0: The client now automatically splits up very large `getEntitiesByRefs` calls into several smaller requests behind the scenes when needed. This ensures that each individual request does not exceed common Express.js request body limits or overload the server. + +### Patch Changes + +- 873f89a: Fix for certain filter fields in the `catalogApiMock` being case sensitive. +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 1.8.0-next.1 ### Minor Changes diff --git a/packages/catalog-client/package.json b/packages/catalog-client/package.json index 6e193132f0..8e16a4bf91 100644 --- a/packages/catalog-client/package.json +++ b/packages/catalog-client/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-client", - "version": "1.8.0-next.1", + "version": "1.9.0-next.2", "description": "An isomorphic client for the catalog backend", "backstage": { "role": "common-library" diff --git a/packages/catalog-client/src/CatalogClient.test.ts b/packages/catalog-client/src/CatalogClient.test.ts index ce44b93b59..ea61634a8b 100644 --- a/packages/catalog-client/src/CatalogClient.test.ts +++ b/packages/catalog-client/src/CatalogClient.test.ts @@ -525,6 +525,18 @@ describe('CatalogClient', () => { '?cursor=prevcursor', ); }); + + it('should handle errors', async () => { + const mockedEndpoint = jest + .fn() + .mockImplementation((_req, res, ctx) => res(ctx.status(401))); + + server.use(rest.get(`${mockBaseUrl}/entities/by-query`, mockedEndpoint)); + + await expect(() => client.queryEntities()).rejects.toThrow( + /Request failed with 401 Unauthorized/, + ); + }); }); describe('getEntityByRef', () => { diff --git a/packages/catalog-client/src/CatalogClient.ts b/packages/catalog-client/src/CatalogClient.ts index 8054063c0b..e820716945 100644 --- a/packages/catalog-client/src/CatalogClient.ts +++ b/packages/catalog-client/src/CatalogClient.ts @@ -237,9 +237,9 @@ export class CatalogClient implements CatalogApi { } } - return this.apiClient - .getEntitiesByQuery({ query: params }, options) - .then(r => r.json()); + return this.requestRequired( + await this.apiClient.getEntitiesByQuery({ query: params }, options), + ); } /** diff --git a/packages/catalog-client/src/schema/openapi/generated/apis/DefaultApi.client.ts b/packages/catalog-client/src/schema/openapi/generated/apis/Api.client.ts similarity index 99% rename from packages/catalog-client/src/schema/openapi/generated/apis/DefaultApi.client.ts rename to packages/catalog-client/src/schema/openapi/generated/apis/Api.client.ts index 11fa561e19..1bf554672c 100644 --- a/packages/catalog-client/src/schema/openapi/generated/apis/DefaultApi.client.ts +++ b/packages/catalog-client/src/schema/openapi/generated/apis/Api.client.ts @@ -22,7 +22,6 @@ import { FetchApi } from '../types/fetch'; import crossFetch from 'cross-fetch'; import { pluginId } from '../pluginId'; import * as parser from 'uri-template'; - import { AnalyzeLocationRequest } from '../models/AnalyzeLocationRequest.model'; import { AnalyzeLocationResponse } from '../models/AnalyzeLocationResponse.model'; import { CreateLocation201Response } from '../models/CreateLocation201Response.model'; @@ -55,7 +54,6 @@ export type TypedResponse = Omit & { export interface RequestOptions { token?: string; } - /** * @public */ @@ -197,7 +195,6 @@ export type ValidateEntity = { }; /** - * no description * @public */ export class DefaultApiClient { diff --git a/packages/catalog-client/src/schema/openapi/generated/apis/index.ts b/packages/catalog-client/src/schema/openapi/generated/apis/index.ts index 51dcca33fe..af52f9db46 100644 --- a/packages/catalog-client/src/schema/openapi/generated/apis/index.ts +++ b/packages/catalog-client/src/schema/openapi/generated/apis/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './DefaultApi.client'; +export * from './Api.client'; diff --git a/packages/catalog-model/CHANGELOG.md b/packages/catalog-model/CHANGELOG.md index 005fd75e58..1e5d752f2f 100644 --- a/packages/catalog-model/CHANGELOG.md +++ b/packages/catalog-model/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/catalog-model +## 1.7.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## 1.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + ## 1.7.0 ### Minor Changes diff --git a/packages/catalog-model/package.json b/packages/catalog-model/package.json index 6e26a011d9..97ebc54888 100644 --- a/packages/catalog-model/package.json +++ b/packages/catalog-model/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/catalog-model", - "version": "1.7.0", + "version": "1.7.2-next.0", "description": "Types and validators that help describe the model of a Backstage Catalog", "backstage": { "role": "common-library" diff --git a/packages/cli-common/CHANGELOG.md b/packages/cli-common/CHANGELOG.md index a47cb36949..4a7880688d 100644 --- a/packages/cli-common/CHANGELOG.md +++ b/packages/cli-common/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/cli-common +## 0.1.15 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` + ## 0.1.15-next.0 ### Patch Changes diff --git a/packages/cli-common/package.json b/packages/cli-common/package.json index 7d406f87b0..d8242fd325 100644 --- a/packages/cli-common/package.json +++ b/packages/cli-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-common", - "version": "0.1.15-next.0", + "version": "0.1.15", "description": "Common functionality used by cli, backend, and create-app", "backstage": { "role": "node-library" diff --git a/packages/cli-node/CHANGELOG.md b/packages/cli-node/CHANGELOG.md index cc1383a375..129564d605 100644 --- a/packages/cli-node/CHANGELOG.md +++ b/packages/cli-node/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/cli-node +## 0.2.11-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/types@1.2.0 + +## 0.2.11-next.0 + +### Patch Changes + +- af665ea: add PackageManager and Lockfile interfaces for future use +- cbfc69e: Internal refactor +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + ## 0.2.10-next.0 ### Patch Changes diff --git a/packages/cli-node/package.json b/packages/cli-node/package.json index ca40403cf5..1aa460550d 100644 --- a/packages/cli-node/package.json +++ b/packages/cli-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli-node", - "version": "0.2.10-next.0", + "version": "0.2.11-next.1", "description": "Node.js library for Backstage CLIs", "backstage": { "role": "node-library" @@ -42,6 +42,7 @@ }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", - "@backstage/cli": "workspace:^" + "@backstage/cli": "workspace:^", + "@backstage/test-utils": "workspace:^" } } diff --git a/packages/cli-node/src/errors.ts b/packages/cli-node/src/errors.ts new file mode 100644 index 0000000000..8be5faeb4f --- /dev/null +++ b/packages/cli-node/src/errors.ts @@ -0,0 +1,32 @@ +/* + * 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 { CustomErrorBase } from '@backstage/errors'; + +export class ExitCodeError extends CustomErrorBase { + readonly code: number; + + constructor(code: number, command?: string) { + super( + command + ? `Command '${command}' exited with code ${code}` + : `Child exited with code ${code}`, + ); + this.code = code; + } +} + +export class NotFoundError extends CustomErrorBase {} diff --git a/packages/cli-node/src/git/GitUtils.ts b/packages/cli-node/src/git/GitUtils.ts index df04b1c6a2..7b87487c56 100644 --- a/packages/cli-node/src/git/GitUtils.ts +++ b/packages/cli-node/src/git/GitUtils.ts @@ -15,8 +15,7 @@ */ import { assertError, ForwardedError } from '@backstage/errors'; -import { paths } from '../paths'; -import { execFile } from '../run'; +import { execFile, paths } from '../util'; /** * Run a git command, trimming the output splitting it into lines. diff --git a/packages/cli-node/src/monorepo/PackageGraph.test.ts b/packages/cli-node/src/monorepo/PackageGraph.test.ts index 9bc9cbf72b..e2378b91c0 100644 --- a/packages/cli-node/src/monorepo/PackageGraph.test.ts +++ b/packages/cli-node/src/monorepo/PackageGraph.test.ts @@ -23,7 +23,7 @@ import { GitUtils } from '../git'; const mockListChangedFiles = jest.spyOn(GitUtils, 'listChangedFiles'); const mockReadFileAtRef = jest.spyOn(GitUtils, 'readFileAtRef'); -jest.mock('../paths', () => ({ +jest.mock('../util', () => ({ paths: { targetRoot: '/', resolveTargetRoot: (...paths: string[]) => resolvePath('/', ...paths), diff --git a/packages/cli-node/src/monorepo/PackageGraph.ts b/packages/cli-node/src/monorepo/PackageGraph.ts index 69ec99c2dd..721aa79e50 100644 --- a/packages/cli-node/src/monorepo/PackageGraph.ts +++ b/packages/cli-node/src/monorepo/PackageGraph.ts @@ -16,7 +16,7 @@ import path from 'path'; import { getPackages, Package } from '@manypkg/get-packages'; -import { paths } from '../paths'; +import { paths } from '../util'; import { PackageRole } from '../roles'; import { GitUtils } from '../git'; import { Lockfile } from './Lockfile'; diff --git a/packages/cli-node/src/monorepo/isMonoRepo.ts b/packages/cli-node/src/monorepo/isMonoRepo.ts index da78c8dd53..f47ac4b9ad 100644 --- a/packages/cli-node/src/monorepo/isMonoRepo.ts +++ b/packages/cli-node/src/monorepo/isMonoRepo.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { paths } from '../paths'; +import { paths } from '../util'; import fs from 'fs-extra'; /** diff --git a/packages/cli-node/src/monorepo/isMonorepo.test.ts b/packages/cli-node/src/monorepo/isMonorepo.test.ts index de0dae0893..30c2d3ccbc 100644 --- a/packages/cli-node/src/monorepo/isMonorepo.test.ts +++ b/packages/cli-node/src/monorepo/isMonorepo.test.ts @@ -19,7 +19,7 @@ import { createMockDirectory } from '@backstage/backend-test-utils'; const mockDir = createMockDirectory(); -jest.mock('../paths', () => ({ +jest.mock('../util', () => ({ paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, })); diff --git a/packages/cli-node/src/pacman/Lockfile.ts b/packages/cli-node/src/pacman/Lockfile.ts new file mode 100644 index 0000000000..51ba07827b --- /dev/null +++ b/packages/cli-node/src/pacman/Lockfile.ts @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/** + * An entry for a single package in a {@link Lockfile}. + * + * @public + */ +export type LockfileEntry = { + range: string; + version: string; +}; + +/** + * An entry for a single difference between two {@link Lockfile}s. + * + * @public + */ +export type LockfileDiffEntry = { + name: string; + range: string; +}; + +/** + * Represents the difference between two {@link Lockfile}s. + * + * @public + */ +export type LockfileDiff = { + added: LockfileDiffEntry[]; + changed: LockfileDiffEntry[]; + removed: LockfileDiffEntry[]; +}; + +/** + * Represents the lockfile for a package manager. + * + * @public + */ +export interface Lockfile { + /** Get the entries for a single package in the lockfile */ + get(name: string): LockfileEntry[] | undefined; + + /** Returns the names of all packages available in the lockfile */ + keys(): IterableIterator; + + /** + * Creates a simplified dependency graph from the lockfile data, where each + * key is a package, and the value is a set of all packages that it depends on + * across all versions. + */ + createSimplifiedDependencyGraph(): Map>; + + /** + * Diff with another lockfile, returning entries that have been + * added, changed, and removed compared to the other lockfile. + */ + diff(otherLockfile: Lockfile): LockfileDiff; + + /** + * Generates a sha1 hex hash of the dependency graph for a package. + */ + getDependencyTreeHash(startName: string): string; +} diff --git a/packages/cli-node/src/pacman/PackageManager.test.ts b/packages/cli-node/src/pacman/PackageManager.test.ts new file mode 100644 index 0000000000..3997da554c --- /dev/null +++ b/packages/cli-node/src/pacman/PackageManager.test.ts @@ -0,0 +1,114 @@ +/* + * 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 { createMockDirectory } from '@backstage/backend-test-utils'; +import { detectPackageManager } from './PackageManager'; +import { Yarn } from './yarn'; +import { withLogCollector } from '@backstage/test-utils'; + +const mockDir = createMockDirectory(); + +jest.mock('../util', () => ({ + ...jest.requireActual('../util'), + paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, +})); + +const mockYarnCreate = jest.spyOn(Yarn, 'create'); + +describe('PackageManager', () => { + describe('detectPackageManager', () => { + describe('yarn', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should detect via yarn.lock', async () => { + mockDir.setContent({ + 'yarn.lock': 'just needs to exist', + }); + await detectPackageManager(); + expect(mockYarnCreate).toHaveBeenCalled(); + }); + + it('should detect via root package.json workspaces', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + workspaces: { + packages: [], + }, + }), + }); + await detectPackageManager(); + expect(mockYarnCreate).toHaveBeenCalled(); + }); + + it('should detect via root package.json packageManager', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + packageManager: 'yarn@1.0.0', + }), + }); + await detectPackageManager(); + expect(mockYarnCreate).toHaveBeenCalled(); + }); + + it('should fall back to yarn when root package.json packageManager field is unrecognized', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + packageManager: 'something-else@1.0.0', + }), + }); + + const { log } = await withLogCollector(async () => { + await detectPackageManager(); + }); + + expect(mockYarnCreate).toHaveBeenCalledTimes(1); + expect(log).toHaveLength(1); + }); + + it('should fall back to yarn with available detection methods', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + }), + }); + + const { log } = await withLogCollector(async () => { + await detectPackageManager(); + }); + + expect(mockYarnCreate).toHaveBeenCalledTimes(1); + expect(log).toHaveLength(1); + }); + + it('should fall back to yarn with no package.json at all', async () => { + mockDir.setContent({}); + + const { log } = await withLogCollector(async () => { + await detectPackageManager(); + }); + + expect(mockYarnCreate).toHaveBeenCalledTimes(1); + // extra log for the error reading package.json + expect(log).toHaveLength(2); + }); + }); + }); +}); diff --git a/packages/cli-node/src/pacman/PackageManager.ts b/packages/cli-node/src/pacman/PackageManager.ts new file mode 100644 index 0000000000..fc0aaa2c97 --- /dev/null +++ b/packages/cli-node/src/pacman/PackageManager.ts @@ -0,0 +1,137 @@ +/* + * 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 { Yarn } from './yarn'; +import { Lockfile } from './Lockfile'; +import { SpawnOptionsPartialEnv, paths } from '../util'; +import fs from 'fs-extra'; + +/** + * Package info retrieved from the package manager, usually from NPM. + * + * @public + */ +export type PackageInfo = { + name: string; + 'dist-tags': Record; + versions: string[]; + time: { [version: string]: string }; +}; + +/** + * Represents the package manager in use by this instance of Backstage. This + * interface allows Backstage adopters to change the package manager used by + * their repo and still use the Backstage CLI, and it's helpful tooling. + * + * @public + */ +export interface PackageManager { + /** The name of the package manager. */ + name(): string; + + /** The self-reported version of the package manager. */ + version(): string; + + /** The file name of the lockfile used by the package manager. */ + lockfileName(): string; + + /** + * If this repo is a monorepo, returns the patterns specified by the package + * manager's monorepo configuration. Does not attempt to resolve any globs. + */ + getMonorepoPackages(): Promise; + + /** Uses the package manager to run a command in the repo. */ + run(args: string[], options?: SpawnOptionsPartialEnv): Promise; + + /** + * Executes the package manager's pack command to bundle the repo into an + * archive. + */ + pack(output: string, packageDir: string): Promise; + + /** Fetches information about the given package, usually from NPM. */ + fetchPackageInfo(name: string): Promise; + + /** Reads the lockfile from the repo. See {@link Lockfile} */ + loadLockfile(): Promise; + + /** Parses the given string as a {@link Lockfile}. */ + parseLockfile(contents: string): Promise; + + /** + * Whether the package manager supports the 'backstage:^' version protocol. + */ + supportsBackstageVersionProtocol(): Promise; + + /** A string representation of the package manager. */ + toString(): string; +} + +/** + * Uses several mechanisms to detect the currently used package manager. The + * detection methods are intended to be ordered roughly from fastest to slowest + * in order to make this method as fast as possible. + * + * @public + */ +export async function detectPackageManager(): Promise { + const hasYarnLockfile = await fileExists( + paths.resolveTargetRoot('yarn.lock'), + ); + if (hasYarnLockfile) { + return await Yarn.create(); + } + + try { + const packageJson = await fs.readJson( + paths.resolveTargetRoot('package.json'), + ); + if (packageJson.workspaces) { + // technically this could be NPM as well + return await Yarn.create(); + } + + const declaredPacman = packageJson.packageManager; + if (declaredPacman) { + const [name, _version] = declaredPacman.split('@'); + switch (name) { + case 'yarn': + return await Yarn.create(); + default: + console.log(`Detected unsupported package manager: ${name}.`); + return await Yarn.create(); + } + } + } catch (error) { + console.log(`Error during package manager detection: ${error}`); + } + + // currently yarn is the only package manager supported so just log an error and use it anyway + console.log( + 'Yarn was not detected, but is the only supported package manager.', + ); + return await Yarn.create(); +} + +async function fileExists(filePath: string): Promise { + try { + await fs.access(filePath); + return true; + } catch (error) { + return false; + } +} diff --git a/packages/cli-node/src/pacman/index.ts b/packages/cli-node/src/pacman/index.ts new file mode 100644 index 0000000000..4e8974d5f8 --- /dev/null +++ b/packages/cli-node/src/pacman/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +export type { PackageManager, PackageInfo } from './PackageManager'; +export type { + Lockfile, + LockfileEntry, + LockfileDiff, + LockfileDiffEntry, +} from './Lockfile'; + +export { detectPackageManager } from './PackageManager'; diff --git a/packages/cli-node/src/pacman/yarn/Yarn.test.ts b/packages/cli-node/src/pacman/yarn/Yarn.test.ts new file mode 100644 index 0000000000..9584ef54b2 --- /dev/null +++ b/packages/cli-node/src/pacman/yarn/Yarn.test.ts @@ -0,0 +1,59 @@ +/* + * 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 { createMockDirectory } from '@backstage/backend-test-utils'; +import { Yarn } from './Yarn'; + +const mockDir = createMockDirectory(); + +jest.mock('../../util', () => ({ + ...jest.requireActual('../../util'), + paths: { resolveTargetRoot: (...args: string[]) => mockDir.resolve(...args) }, +})); + +const yarnClassic = new Yarn({ version: '1.0.0', codename: 'classic' }); +const yarnBerry = new Yarn({ version: '3.0.0', codename: 'berry' }); +const allYarnVersions = [yarnClassic, yarnBerry]; + +describe('Yarn', () => { + describe.each(allYarnVersions)('%s.getMonorepoPackages', yarn => { + it('should detect a monorepo', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + workspaces: { + packages: ['packages/*'], + }, + }), + }); + await expect(yarn.getMonorepoPackages()).resolves.toEqual(['packages/*']); + }); + + it('should detect a non-monorepo', async () => { + mockDir.setContent({ + 'package.json': JSON.stringify({ + name: 'foo', + }), + }); + await expect(yarn.getMonorepoPackages()).resolves.toEqual([]); + }); + + it('should return false if package.json is missing', async () => { + mockDir.setContent({}); + await expect(yarn.getMonorepoPackages()).resolves.toEqual([]); + }); + }); +}); diff --git a/packages/cli-node/src/pacman/yarn/Yarn.ts b/packages/cli-node/src/pacman/yarn/Yarn.ts new file mode 100644 index 0000000000..0a2b8d55ea --- /dev/null +++ b/packages/cli-node/src/pacman/yarn/Yarn.ts @@ -0,0 +1,121 @@ +/* + * 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 { + assertError, + ForwardedError, + NotImplementedError, +} from '@backstage/errors'; +import { PackageInfo, PackageManager } from '../PackageManager'; +import { Lockfile } from '../Lockfile'; +import { YarnVersion } from './types'; +import fs from 'fs-extra'; +import { paths, run, execFile, SpawnOptionsPartialEnv } from '../../util'; + +export class Yarn implements PackageManager { + constructor(private readonly yarnVersion: YarnVersion) {} + + static async create(dir?: string): Promise { + const yarnVersion = await detectYarnVersion(dir); + return new Yarn(yarnVersion); + } + + name() { + return 'yarn'; + } + + version() { + return this.yarnVersion.version; + } + + lockfileName(): string { + return 'yarn.lock'; + } + + async getMonorepoPackages() { + const rootPackageJsonPath = paths.resolveTargetRoot('package.json'); + try { + const pkg = await fs.readJson(rootPackageJsonPath); + return pkg?.workspaces?.packages || []; + } catch (error) { + return []; + } + } + + async pack(out: string, packageDir: string) { + const outArg = + this.yarnVersion.codename === 'classic' ? '--filename' : '--out'; + await this.run(['pack', outArg, out], { + cwd: packageDir, + }); + } + + async run(args: string[], options?: SpawnOptionsPartialEnv) { + await run('yarn', args, options); + } + + async fetchPackageInfo(): Promise { + throw new NotImplementedError(); + } + + async loadLockfile(): Promise { + throw new NotImplementedError(); + } + + async parseLockfile(): Promise { + throw new NotImplementedError(); + } + + async supportsBackstageVersionProtocol(): Promise { + throw new NotImplementedError(); + } + + toString(): string { + return `${this.name()}@${this.yarnVersion.version}`; + } +} + +const versions = new Map>(); + +function detectYarnVersion(dir?: string): Promise { + const cwd = dir ?? process.cwd(); + if (versions.has(cwd)) { + return versions.get(cwd)!; + } + + const promise = Promise.resolve().then(async () => { + try { + const { stdout } = await execFile('yarn', ['--version'], { + shell: true, + cwd, + }); + const versionString = stdout.trim(); + const codename: 'classic' | 'berry' = versionString.startsWith('1.') + ? 'classic' + : 'berry'; + return { version: versionString, codename }; + } catch (error) { + assertError(error); + if ('stderr' in error) { + process.stderr.write(error.stderr as Buffer); + } + throw new ForwardedError('Failed to determine yarn version', error); + } + }); + + versions.set(cwd, promise); + return promise; +} diff --git a/packages/cli-node/src/pacman/yarn/index.ts b/packages/cli-node/src/pacman/yarn/index.ts new file mode 100644 index 0000000000..a0998d50c4 --- /dev/null +++ b/packages/cli-node/src/pacman/yarn/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export { Yarn } from './Yarn'; diff --git a/packages/cli-node/src/pacman/yarn/types.ts b/packages/cli-node/src/pacman/yarn/types.ts new file mode 100644 index 0000000000..f7ba98f706 --- /dev/null +++ b/packages/cli-node/src/pacman/yarn/types.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ +export type YarnVersion = { + codename: 'classic' | 'berry'; + version: string; +}; diff --git a/packages/cli-node/src/util.ts b/packages/cli-node/src/util.ts new file mode 100644 index 0000000000..eaf05855b1 --- /dev/null +++ b/packages/cli-node/src/util.ts @@ -0,0 +1,109 @@ +/* + * 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 { + ChildProcess, + execFile as execFileCb, + spawn, + SpawnOptions, +} from 'child_process'; +import { promisify } from 'util'; +import { findPaths } from '@backstage/cli-common'; +import { ExitCodeError } from './errors'; + +export const execFile = promisify(execFileCb); + +/* eslint-disable-next-line no-restricted-syntax */ +export const paths = findPaths(__dirname); + +/** + * A function that can be used to log data from a child process + * + * @public + */ +export type LogFunc = (data: Buffer) => void; + +/** + * Options for running a child process + * + * @public + */ +export type SpawnOptionsPartialEnv = Omit & { + env?: Partial; + // Pipe stdout to this log function + stdoutLogFunc?: LogFunc; + // Pipe stderr to this log function + stderrLogFunc?: LogFunc; +}; + +// Runs a child command, returning a promise that is only resolved if the child exits with code 0. +export async function run( + name: string, + args: string[] = [], + options: SpawnOptionsPartialEnv = {}, +) { + const { stdoutLogFunc, stderrLogFunc } = options; + const env: NodeJS.ProcessEnv = { + ...process.env, + FORCE_COLOR: 'true', + ...(options.env ?? {}), + }; + + const stdio = [ + 'inherit', + stdoutLogFunc ? 'pipe' : 'inherit', + stderrLogFunc ? 'pipe' : 'inherit', + ] as ('inherit' | 'pipe')[]; + + const child = spawn(name, args, { + stdio, + shell: true, + ...options, + env, + }); + + if (stdoutLogFunc && child.stdout) { + child.stdout.on('data', stdoutLogFunc); + } + if (stderrLogFunc && child.stderr) { + child.stderr.on('data', stderrLogFunc); + } + + await waitForExit(child, name); +} + +async function waitForExit( + child: ChildProcess & { exitCode: number | null }, + name?: string, +): Promise { + if (typeof child.exitCode === 'number') { + if (child.exitCode) { + throw new ExitCodeError(child.exitCode, name); + } + return; + } + + await new Promise((resolve, reject) => { + child.once('error', error => reject(error)); + child.once('exit', code => { + if (code) { + reject(new ExitCodeError(code, name)); + } else { + resolve(); + } + }); + }); +} diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 32a5eaf164..f8dd593d52 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,135 @@ # @backstage/cli +## 0.29.3-next.2 + +### Patch Changes + +- 62a9062: Updated dependency `@module-federation/enhanced` to `^0.8.0`. +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.16.0-next.1 + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/types@1.2.0 + +## 0.29.3-next.1 + +### Patch Changes + +- a49030a: Add support for `--output-file` option from ESLint to `package lint` and `repo lint` commands. +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## 0.29.3-next.0 + +### Patch Changes + +- 2b6c1ea: If the Backstage yarn plugin is installed, it will now be automatically updated as part of `versions:bump`. +- 7dcff85: Remove special-casing for `@types` packages when generating dependency entries + during templating +- 0aff006: Bumped the version range for `html-webpack-plugin` to fix the `htmlPluginExports.getCompilationHooks is not a function` error when using experimental Rspack. +- 583f3d4: Added `@backstage/cli/config/prettier` as a replacement for `@spotify/prettier-config`, but with the same configuration. +- 5f04976: Update `rollup` to avoid issues with build output when running `backstage-cli package build`. +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/release-manifests@0.0.12-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/types@1.2.0 + +## 0.29.0 + +### Minor Changes + +- bc47b17: **BREAKING**: Updates ESLint config to ignore all generated source code under `src/**/generated/**/*.ts`. +- 6819f8c: Added a new optimization to the `repo test` command that will filter out unused packages in watch mode if all provide filters are paths that point from the repo root. This significantly speeds up running individual tests from the repo root in a large workspace, for example: + + ```sh + yarn test packages/app/src/App.test.tsx + ``` + +- d849865: The package packing now populates `typesVersions` for additional entry points rather than using additional `package.json` files for type resolution. This improves auto completion of separate entry points when consuming published packages. +- bc71665: **BREAKING**: The `LEGACY_BACKEND_START` flag has been removed, along with support for `src/run.ts` as the development entry point. + +### Patch Changes + +- 4046d53: Fixed an issue where the `--successCache` option for the `repo test` and `repo lint` commands would be include the workspace path in generated cache keys. This previously broke caching in environments where the workspace path varies across builds. +- 4a378d3: Fix dev server reloads of plugin discovery for new frontend system. +- 28b60ad: The check for `react-dom/client` in the Jest configuration will now properly always run from the target directory. +- 6b2888c: Fixed an issue with the `--successCache` flag for `repo test` where the tree hash for the wrong package directory would sometimes be used to generate the cache key. +- e30b65d: Added `--alwaysPack` as a replacement for the now hidden `--alwaysYarnPack` flag for the `build-workspace` command. +- be0278e: Removed circular import +- a7f97e4: Added a new `"rejectFrontendNetworkRequests"` configuration flag that can be set in the `"jest"` field in the root `package.json`: + + ```json + { + "jest": { + "rejectFrontendNetworkRequests": true + } + } + ``` + + This flag causes rejection of any form of network requests that are attempted to be made in frontend or common package tests. This flag can only be set in the root `package.json` and can not be overridden in individual package configurations. + +- 6c48ebd: Add `--max-warnings -1` support to `backstage-cli package lint` +- 04297a0: The `--successCache` option for the `repo test` and `repo lint` commands now use an additive store that keeps old entries around for a week before they are cleaned up automatically. +- a2f0559: When using the experimental Rspack flag the app build and dev server now injects configuration via a `` tag in `index.html` rather than the `process.env.APP_CONFIG` definition, which will now be defined as an empty array instead. + + This requires the app to be using the config loader from the 1.31 release of Backstage. Make sure your app is using at least that version if you are upgrading to this version of the CLI. + + If you have copied the implementation of the `defaultConfigLoader`, make sure to update it to the new implementation. In particular the config loader needs to be able to read configuration from `script` tags with the type `backstage.io/config`. + +- b4627f2: Fixed an issue where the `raw-loader` for loading HTML templates was not resolved from the context of the CLI package. +- cd1ef2b: Updated dependency `vite` to `^5.0.0`. +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. +- b533056: Updated dependency `css-loader` to `^7.0.0`. +- be008c3: Updated dependency `@module-federation/enhanced` to `^0.7.0`. +- 6266ed3: Updated dependency `del` to `^8.0.0`. +- 4046d53: Fixed an issue with the `repo lint` command where the cache key for the `--successCache` option would not properly ignore files that should be ignored according to `.eslintignore`s. +- e19c53c: Fix for the `--link` flag for `package start` to deduplicate `react-router` and `react-router-dom`. +- 17850a5: Update upgrade-helper link in `versions:bump` command to include `yarnPlugin` parameter when the yarn plugin is installed +- 09ea093: Fixed an issue where `.css` style injection would fail for published packages. +- 702f41d: Bumped dev dependencies `@types/node` +- 5d74716: Remove unused backend-common dependency +- b084f5a: Bump the Webpack dependency range to `^5.94.0`, as our current configuration is not compatible with some older versions. +- e565f73: Added support for `.webp` files in the frontend tooling. +- 946fa34: Added a new `--link ` option for frontend builds that allow you to override module resolution to link in an external workspace at runtime. + + As part of this change the Webpack linked workspace resolution plugin for frontend builds has been removed. It was in place to support the old workspace linking where it was done by Yarn, which is no longer a working option. + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + - @backstage/eslint-plugin@0.1.10 + - @backstage/integration@1.15.2 + - @backstage/release-manifests@0.0.11 + ## 0.29.0-next.3 ### Minor Changes diff --git a/packages/cli-node/src/run.ts b/packages/cli/bin/backstage-cli-alpha old mode 100644 new mode 100755 similarity index 81% rename from packages/cli-node/src/run.ts rename to packages/cli/bin/backstage-cli-alpha index e924b5c5b8..38a2df3319 --- a/packages/cli-node/src/run.ts +++ b/packages/cli/bin/backstage-cli-alpha @@ -1,3 +1,4 @@ +#!/usr/bin/env node /* * Copyright 2020 The Backstage Authors * @@ -14,7 +15,5 @@ * limitations under the License. */ -import { execFile as execFileCb } from 'child_process'; -import { promisify } from 'util'; - -export const execFile = promisify(execFileCb); +require('@backstage/cli/config/nodeTransform.cjs'); +require('../src/alpha'); diff --git a/packages/cli/cli-report.md b/packages/cli/cli-report.md index 3fa7198eba..d9fec4db22 100644 --- a/packages/cli/cli-report.md +++ b/packages/cli/cli-report.md @@ -236,6 +236,7 @@ Usage: backstage-cli package lint [options] [directories...] Options: --format + --output-file --fix --max-warnings -h, --help @@ -446,6 +447,7 @@ Usage: backstage-cli repo lint [options] Options: --format + --output-file --since --successCache --successCacheDir diff --git a/packages/cli/config/nodeTransform.cjs b/packages/cli/config/nodeTransform.cjs index fc25044fd0..1cf79cb1bb 100644 --- a/packages/cli/config/nodeTransform.cjs +++ b/packages/cli/config/nodeTransform.cjs @@ -41,7 +41,7 @@ if (process.env.BACKSTAGE_CLI_LINKED_WORKSPACE) { } // The package import that we're overriding will always existing in the root - // node_modules of the linked workspace, so it's enough to override the the + // node_modules of the linked workspace, so it's enough to override the // parent paths with that single entry return origLoad.call(this, request, { ...parent, diff --git a/packages/cli/config/prettier.json b/packages/cli/config/prettier.json new file mode 100644 index 0000000000..5393aaf2da --- /dev/null +++ b/packages/cli/config/prettier.json @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid" +} diff --git a/packages/cli/package.json b/packages/cli/package.json index bc4d0dda29..9d93f6007b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/cli", - "version": "0.29.0-next.3", + "version": "0.29.3-next.2", "description": "CLI for developing Backstage plugins and apps", "backstage": { "role": "cli" @@ -53,7 +53,7 @@ "@backstage/release-manifests": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@module-federation/enhanced": "^0.7.0", + "@module-federation/enhanced": "^0.8.0", "@octokit/graphql": "^5.0.0", "@octokit/graphql-schema": "^13.7.0", "@octokit/oauth-app": "^4.2.0", @@ -88,7 +88,7 @@ "commander": "^12.0.0", "cross-fetch": "^4.0.0", "cross-spawn": "^7.0.3", - "css-loader": "^7.0.0", + "css-loader": "^6.5.1", "ctrlc-windows": "^2.1.0", "esbuild": "^0.24.0", "esbuild-loader": "^4.0.0", @@ -111,7 +111,7 @@ "global-agent": "^3.0.0", "globby": "^11.1.0", "handlebars": "^4.7.3", - "html-webpack-plugin": "^5.3.1", + "html-webpack-plugin": "^5.6.3", "inquirer": "^8.2.0", "jest": "^29.7.0", "jest-cli": "^29.7.0", @@ -122,7 +122,6 @@ "lodash": "^4.17.21", "mini-css-extract-plugin": "^2.4.2", "minimatch": "^9.0.0", - "node-fetch": "^2.7.0", "node-libs-browser": "^2.2.1", "npm-packlist": "^5.0.0", "ora": "^5.3.0", @@ -136,7 +135,7 @@ "react-refresh": "^0.14.0", "recursive-readdir": "^2.2.2", "replace-in-file": "^7.1.0", - "rollup": "^4.0.0", + "rollup": "^4.27.3", "rollup-plugin-dts": "^6.1.0", "rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-postcss": "^4.0.0", diff --git a/packages/cli/src/alpha.ts b/packages/cli/src/alpha.ts new file mode 100644 index 0000000000..4b2cfa4842 --- /dev/null +++ b/packages/cli/src/alpha.ts @@ -0,0 +1,29 @@ +/* + * 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 () => { + console.warn( + 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/config/alpha').then(m => m.default)); + await initializer.run(); +})(); diff --git a/packages/cli/src/commands/build/buildFrontend.ts b/packages/cli/src/commands/build/buildFrontend.ts index 59f3225738..0ba0669c32 100644 --- a/packages/cli/src/commands/build/buildFrontend.ts +++ b/packages/cli/src/commands/build/buildFrontend.ts @@ -18,7 +18,7 @@ import fs from 'fs-extra'; import { resolve as resolvePath } from 'path'; import { buildBundle, getModuleFederationOptions } from '../../lib/bundler'; import { getEnvironmentParallelism } from '../../lib/parallel'; -import { loadCliConfig } from '../../lib/config'; +import { loadCliConfig } from '../../modules/config/lib/config'; interface BuildAppOptions { targetDir: string; diff --git a/packages/cli/src/commands/create-github-app/index.ts b/packages/cli/src/commands/create-github-app/index.ts index 681b471c91..105a6b4c24 100644 --- a/packages/cli/src/commands/create-github-app/index.ts +++ b/packages/cli/src/commands/create-github-app/index.ts @@ -20,7 +20,6 @@ import { stringify as stringifyYaml } from 'yaml'; import inquirer, { Question, Answers } from 'inquirer'; import { paths } from '../../lib/paths'; import { GithubCreateAppServer } from './GithubCreateAppServer'; -import fetch from 'node-fetch'; import openBrowser from 'react-dev-utils/openBrowser'; // This is an experimental command that at this point does not support GitHub Enterprise diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 2a77d527c1..0f38fc1e8a 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -15,15 +15,11 @@ */ import { Command, Option } from 'commander'; -import { assertError } from '@backstage/errors'; -import { exitWithError } from '../lib/errors'; - -const configOption = [ - '--config ', - 'Config files to load instead of app-config.yaml', - (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), - Array(), -] as const; +import { lazy } from '../lib/lazy'; +import { + configOption, + registerCommands as registerConfigCommands, +} from '../modules/config'; export function registerRepoCommand(program: Command) { const command = program @@ -57,6 +53,10 @@ export function registerRepoCommand(program: Command) { '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', @@ -172,6 +172,10 @@ export function registerScriptCommand(program: Command) { '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 ', @@ -279,66 +283,7 @@ export function registerCommands(program: Command) { .option('--no-private', 'Do not mark new packages as private') .action(lazy(() => import('./new/new').then(m => m.default))); - 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('./config/docs').then(m => m.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('./config/print').then(m => m.default))); - - 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('./config/validate').then(m => m.default))); - - 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('./config/schema').then(m => m.default))); - + registerConfigCommands(program); registerRepoCommand(program); registerScriptCommand(program); registerMigrateCommand(program); @@ -444,20 +389,3 @@ function removed(message?: string) { process.exit(1); }; } - -// Wraps an action function so that it always exits and handles errors -function lazy( - getActionFunc: () => Promise<(...args: any[]) => Promise>, -): (...args: any[]) => Promise { - return async (...args: any[]) => { - try { - const actionFunc = await getActionFunc(); - await actionFunc(...args); - - process.exit(0); - } catch (error) { - assertError(error); - exitWithError(error); - } - }; -} diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts index 0c67d84c86..8c8877c19c 100644 --- a/packages/cli/src/commands/lint.ts +++ b/packages/cli/src/commands/lint.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import fs from 'fs-extra'; import { OptionValues } from 'commander'; import { paths } from '../lib/paths'; import { ESLint } from 'eslint'; @@ -49,10 +50,14 @@ export default async (directories: string[], opts: OptionValues) => { process.chdir(paths.targetRoot); } - const resultText = formatter.format(results); + const resultText = await formatter.format(results); if (resultText) { - console.log(resultText); + if (opts.outputFile) { + await fs.writeFile(paths.resolveTarget(opts.outputFile), resultText); + } else { + console.log(resultText); + } } if (failed) { diff --git a/packages/cli/src/commands/repo/build.ts b/packages/cli/src/commands/repo/build.ts index 7e6d235e7d..cd5e32dd06 100644 --- a/packages/cli/src/commands/repo/build.ts +++ b/packages/cli/src/commands/repo/build.ts @@ -31,6 +31,11 @@ import { createScriptOptionsParser } from './optionsParser'; export async function command(opts: OptionValues, cmd: Command): Promise { let packages = await PackageGraph.listTargetPackages(); + const shouldUseRspack = Boolean(process.env.EXPERIMENTAL_RSPACK); + + const rspack = shouldUseRspack + ? (require('@rspack/core') as typeof import('@rspack/core').rspack) + : undefined; if (opts.since) { const graph = PackageGraph.fromPackages(packages); @@ -111,6 +116,7 @@ export async function command(opts: OptionValues, cmd: Command): Promise { targetDir: pkg.dir, configPaths: (buildOptions.config as string[]) ?? [], writeStats: Boolean(buildOptions.stats), + rspack, }); }, }); diff --git a/packages/cli/src/commands/repo/lint.ts b/packages/cli/src/commands/repo/lint.ts index 7be021f8dd..f78b51ea5d 100644 --- a/packages/cli/src/commands/repo/lint.ts +++ b/packages/cli/src/commands/repo/lint.ts @@ -15,6 +15,7 @@ */ import chalk from 'chalk'; +import fs from 'fs-extra'; import { Command, OptionValues } from 'commander'; import { createHash } from 'crypto'; import { relative as relativePath } from 'path'; @@ -220,6 +221,8 @@ export async function command(opts: OptionValues, cmd: Command): Promise { const outputSuccessCache = []; + let errorOutput = ''; + let failed = false; for (const { relativeDir, @@ -234,14 +237,22 @@ export async function command(opts: OptionValues, cmd: Command): Promise { // When doing repo lint, only list the results if the lint failed to avoid a log // dump of all warnings that might be irrelevant if (resultText) { - console.log(); - console.log(resultText.trimStart()); + if (opts.outputFile) { + errorOutput += `${resultText}\n`; + } else { + console.log(); + console.log(resultText.trimStart()); + } } } else if (sha) { outputSuccessCache.push(sha); } } + if (opts.outputFile && errorOutput) { + await fs.writeFile(paths.resolveTargetRoot(opts.outputFile), errorOutput); + } + if (cacheContext) { await cache.write(outputSuccessCache); } diff --git a/packages/cli/src/commands/versions/bump.test.ts b/packages/cli/src/commands/versions/bump.test.ts index cc48b91fd8..96e8de517b 100644 --- a/packages/cli/src/commands/versions/bump.test.ts +++ b/packages/cli/src/commands/versions/bump.test.ts @@ -33,6 +33,7 @@ jest.mock('global-agent/bootstrap', () => {}); // Remove log coloring to simplify log matching jest.mock('chalk', () => ({ + bold: (str: string) => str, red: (str: string) => str, blue: (str: string) => str, cyan: (str: string) => str, @@ -90,6 +91,12 @@ const REGISTRY_VERSIONS: { [name: string]: string } = { '@backstage/create-app': '1.0.0', }; +const yarnRcMock = `plugins: + - checksum: cafedead + path: .yarn/plugins/@yarnpkg/plugin-backstage.cjs + spec: 'https://versions.backstage.io/v1/releases/0.0.0/yarn-plugin' +`; + const HEADER = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 @@ -435,6 +442,117 @@ describe('bump', () => { }); }); + it('should use backstage:^ versions for packages in the release manifest when the yarn plugin is installed', async () => { + mockDir.setContent({ + '.yarnrc.yml': yarnRcMock, + 'yarn.lock': lockfileMock, + 'package.json': JSON.stringify({ + workspaces: { + packages: ['packages/*'], + }, + }), + packages: { + a: { + 'package.json': JSON.stringify({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.5', + }, + }), + }, + b: { + 'package.json': JSON.stringify({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.3', + '@backstage/theme': '^1.0.0', + }, + }), + }, + }, + }); + + jest.spyOn(runObj, 'run').mockResolvedValue(undefined); + worker.use( + rest.get( + 'https://versions.backstage.io/v1/tags/main/manifest.json', + (_, res, ctx) => + res( + ctx.status(200), + ctx.json({ + releaseVersion: '0.0.1', + packages: [ + { + name: '@backstage/theme', + version: '5.0.0', + }, + { + name: '@backstage/create-app', + version: '3.0.0', + }, + ], + }), + ), + ), + ); + const { log: logs } = await withLogCollector(['log', 'warn'], async () => { + await bump({ pattern: null, release: 'main' } as unknown as Command); + }); + expectLogsToMatch(logs, [ + 'Using default pattern glob @backstage/*', + 'Checking for updates of @backstage/core', + 'Checking for updates of @backstage/theme', + 'NOTE: this bump used backstage:^ versions in package.json files, since the Backstage yarn plugin was detected in the repository. To migrate back to explicit npm versions, remove the plugin by running "yarn plugin remove @yarnpkg/plugin-backstage", then repeat this command.', + 'Some packages are outdated, updating', + 'bumping @backstage/theme in b to ^5.0.0', + 'bumping @backstage/core in b to ^1.0.6', + 'bumping @backstage/core in a to ^1.0.6', + 'Updating yarn plugin to v0.0.1...', + 'Your project is now at version 0.0.1, which has been written to backstage.json', + 'Running yarn install to install new versions', + 'Checking for moved packages to the @backstage-community namespace...', + '⚠️ The following packages may have breaking changes:', + ' @backstage/theme : 1.0.0 ~> 5.0.0', + ' https://github.com/backstage/backstage/blob/master/packages/theme/CHANGELOG.md', + 'Version bump complete!', + ]); + + expect(mockFetchPackageInfo).toHaveBeenCalledTimes(1); + expect(mockFetchPackageInfo).toHaveBeenCalledWith('@backstage/core'); + + expect(runObj.run).toHaveBeenCalledTimes(2); + expect(runObj.run).toHaveBeenCalledWith('yarn', [ + 'plugin', + 'import', + 'https://versions.backstage.io/v1/releases/0.0.1/yarn-plugin', + ]); + expect(runObj.run).toHaveBeenCalledWith( + 'yarn', + ['install'], + expect.any(Object), + ); + + const packageA = await fs.readJson( + mockDir.resolve('packages/a/package.json'), + ); + expect(packageA).toEqual({ + name: 'a', + dependencies: { + '@backstage/core': '^1.0.6', + }, + }); + const packageB = await fs.readJson( + mockDir.resolve('packages/b/package.json'), + ); + expect(packageB).toEqual({ + name: 'b', + dependencies: { + '@backstage/core': '^1.0.6', + '@backstage/theme': 'backstage:^', + }, + }); + }); + it('should only bump packages in the manifest when a specific release is specified', async () => { mockDir.setContent({ 'yarn.lock': lockfileMock, diff --git a/packages/cli/src/commands/versions/bump.ts b/packages/cli/src/commands/versions/bump.ts index 8d43f38967..76e6092140 100644 --- a/packages/cli/src/commands/versions/bump.ts +++ b/packages/cli/src/commands/versions/bump.ts @@ -22,14 +22,12 @@ if (shouldUseGlobalAgent()) { import fs from 'fs-extra'; import chalk from 'chalk'; -import ora from 'ora'; import semver from 'semver'; import { OptionValues } from 'commander'; import yaml from 'yaml'; import z from 'zod'; import { isError, NotFoundError } from '@backstage/errors'; import { resolve as resolvePath } from 'path'; -import { run } from '../../lib/run'; import { paths } from '../../lib/paths'; import { mapDependencies, @@ -45,6 +43,8 @@ import { ReleaseManifest, } from '@backstage/release-manifests'; import { migrateMovedPackages } from './migrate'; +import { runYarnInstall } from './utils'; +import { run } from '../../lib/run'; function shouldUseGlobalAgent(): boolean { // see https://www.npmjs.com/package/global-agent @@ -121,6 +121,20 @@ export default async (opts: OptionValues) => { }); } + if (hasYarnPlugin) { + console.log(); + console.log( + `Updating yarn plugin to v${releaseManifest.releaseVersion}...`, + ); + console.log(); + await run('yarn', [ + 'plugin', + 'import', + `https://versions.backstage.io/v1/releases/${releaseManifest.releaseVersion}/yarn-plugin`, + ]); + console.log(); + } + // First we discover all Backstage dependencies within our own repo const dependencyMap = await mapDependencies(paths.targetDir, pattern); @@ -508,35 +522,3 @@ async function getHasYarnPlugin() { plugin => plugin.path === '.yarn/plugins/@yarnpkg/plugin-backstage.cjs', ); } - -export async function runYarnInstall() { - const spinner = ora({ - prefixText: `Running ${chalk.blue('yarn install')} to install new versions`, - spinner: 'arc', - color: 'green', - }).start(); - - const installOutput = new Array(); - try { - await run('yarn', ['install'], { - env: { - FORCE_COLOR: 'true', - // We filter out all of the npm_* environment variables that are added when - // executing through yarn. This works around an issue where these variables - // incorrectly override local yarn or npm config in the project directory. - ...Object.fromEntries( - Object.entries(process.env).map(([name, value]) => - name.startsWith('npm_') ? [name, undefined] : [name, value], - ), - ), - }, - stdoutLogFunc: data => installOutput.push(data), - stderrLogFunc: data => installOutput.push(data), - }); - spinner.succeed(); - } catch (error) { - spinner.fail(); - process.stdout.write(Buffer.concat(installOutput)); - throw error; - } -} diff --git a/packages/cli/src/commands/versions/migrate.ts b/packages/cli/src/commands/versions/migrate.ts index 321a78ef9f..8415de0f57 100644 --- a/packages/cli/src/commands/versions/migrate.ts +++ b/packages/cli/src/commands/versions/migrate.ts @@ -19,7 +19,7 @@ import { resolve as resolvePath, join as joinPath } from 'path'; import { OptionValues } from 'commander'; import { readJson, writeJson } from 'fs-extra'; import { minimatch } from 'minimatch'; -import { runYarnInstall } from './bump'; +import { runYarnInstall } from './utils'; import replace from 'replace-in-file'; declare module 'replace-in-file' { diff --git a/packages/cli/src/commands/versions/utils.ts b/packages/cli/src/commands/versions/utils.ts new file mode 100644 index 0000000000..22c5f0c028 --- /dev/null +++ b/packages/cli/src/commands/versions/utils.ts @@ -0,0 +1,51 @@ +/* + * 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 ora from 'ora'; +import chalk from 'chalk'; +import { run } from '../../lib/run'; + +export async function runYarnInstall() { + const spinner = ora({ + prefixText: `Running ${chalk.blue('yarn install')} to install new versions`, + spinner: 'arc', + color: 'green', + }).start(); + + const installOutput = new Array(); + try { + await run('yarn', ['install'], { + env: { + FORCE_COLOR: 'true', + // We filter out all of the npm_* environment variables that are added when + // executing through yarn. This works around an issue where these variables + // incorrectly override local yarn or npm config in the project directory. + ...Object.fromEntries( + Object.entries(process.env).map(([name, value]) => + name.startsWith('npm_') ? [name, undefined] : [name, value], + ), + ), + }, + stdoutLogFunc: data => installOutput.push(data), + stderrLogFunc: data => installOutput.push(data), + }); + spinner.succeed(); + } catch (error) { + spinner.fail(); + process.stdout.write(Buffer.concat(installOutput)); + throw error; + } +} diff --git a/packages/cli/src/lib/bundler/ConfigInjectingHtmlWebpackPlugin.ts b/packages/cli/src/lib/bundler/ConfigInjectingHtmlWebpackPlugin.ts new file mode 100644 index 0000000000..5aa8b75098 --- /dev/null +++ b/packages/cli/src/lib/bundler/ConfigInjectingHtmlWebpackPlugin.ts @@ -0,0 +1,55 @@ +/* + * 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 { AppConfig } from '@backstage/config'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; + +export class ConfigInjectingHtmlWebpackPlugin extends HtmlWebpackPlugin { + readonly name = 'ConfigInjectingHtmlWebpackPlugin'; + readonly #getFrontendAppConfigs: () => AppConfig[]; + + constructor( + options: HtmlWebpackPlugin.Options, + getFrontendAppConfigs: () => AppConfig[], + ) { + super(options); + this.#getFrontendAppConfigs = getFrontendAppConfigs; + } + + apply: HtmlWebpackPlugin['apply'] = compiler => { + super.apply(compiler); + + compiler.hooks.compilation.tap(this.name, compilation => { + const hooks = HtmlWebpackPlugin.getCompilationHooks(compilation); + hooks.alterAssetTagGroups.tap(this.name, ctx => { + if (ctx.plugin !== this) { + return ctx; + } + return { + ...ctx, + headTags: [ + ...ctx.headTags, + HtmlWebpackPlugin.createHtmlTagObject( + 'script', + { type: 'backstage.io/config' }, + `\n${JSON.stringify(this.#getFrontendAppConfigs(), null, 2)}\n`, + ), + ], + }; + }); + }); + }; +} diff --git a/packages/cli/src/lib/bundler/bundle.ts b/packages/cli/src/lib/bundler/bundle.ts index cb0322eb2c..7d88a2f97f 100644 --- a/packages/cli/src/lib/bundler/bundle.ts +++ b/packages/cli/src/lib/bundler/bundle.ts @@ -119,6 +119,12 @@ export async function buildBundle(options: BuildOptions) { ); } + if (rspack) { + console.log( + chalk.yellow(`⚠️ WARNING: Using experimental RSPack bundler.`), + ); + } + const { stats } = await build(configs, isCi, rspack); if (!stats) { diff --git a/packages/cli/src/lib/bundler/config.ts b/packages/cli/src/lib/bundler/config.ts index 4e9f67c4fa..5e379783ba 100644 --- a/packages/cli/src/lib/bundler/config.ts +++ b/packages/cli/src/lib/bundler/config.ts @@ -37,6 +37,7 @@ import { version } from '../../lib/version'; import yn from 'yn'; import { hasReactDomClient } from './hasReactDomClient'; import { createWorkspaceLinkingPlugins } from './linkWorkspaces'; +import { ConfigInjectingHtmlWebpackPlugin } from './ConfigInjectingHtmlWebpackPlugin'; const BUILD_CACHE_ENV_VAR = 'BACKSTAGE_CLI_EXPERIMENTAL_BUILD_CACHE'; @@ -182,19 +183,35 @@ export async function createConfig( ); if (options.moduleFederation?.mode !== 'remote') { - plugins.push( - // `rspack.HtmlRspackPlugin` does not support object type `templateParameters` value, `frontendConfig` in this case - new HtmlWebpackPlugin({ - meta: { - 'backstage-app-mode': options?.appMode ?? 'public', - }, - template: paths.targetHtml, - templateParameters: { - publicPath, - config: frontendConfig, - }, - }), - ); + const templateOptions = { + meta: { + 'backstage-app-mode': options?.appMode ?? 'public', + }, + template: paths.targetHtml, + templateParameters: { + publicPath, + config: frontendConfig, + }, + }; + if (rspack) { + // With Rspack we inject config via index.html, this is both because we + // can't use APP_CONFIG due to the lack of support for runtime values, but + // also because we are able to do it and it lines up better with what the + // app-backend is doing. + // + // We still use the html plugin from WebPack, since the Rspack one won't + // let us inject complex objects like the config. + plugins.push( + new ConfigInjectingHtmlWebpackPlugin( + templateOptions, + options.getFrontendAppConfigs, + ), + ); + } else { + // Config injection via index.html doesn't work across reloads with + // WebPack, so we rely on the APP_CONFIG injection instead + plugins.push(new HtmlWebpackPlugin(templateOptions)); + } plugins.push( new HtmlWebpackPlugin({ meta: { @@ -284,8 +301,7 @@ export async function createConfig( new bundler.DefinePlugin({ 'process.env.BUILD_INFO': JSON.stringify(buildInfo), 'process.env.APP_CONFIG': rspack - ? // FIXME: see also https://github.com/web-infra-dev/rspack/issues/5606 - JSON.stringify(options.getFrontendAppConfigs()) + ? JSON.stringify([]) // Inject via index.html instead : bundler.DefinePlugin.runtimeValue( () => JSON.stringify(options.getFrontendAppConfigs()), true, diff --git a/packages/cli/src/lib/bundler/server.ts b/packages/cli/src/lib/bundler/server.ts index 44d6d54379..1b62c82ce5 100644 --- a/packages/cli/src/lib/bundler/server.ts +++ b/packages/cli/src/lib/bundler/server.ts @@ -22,7 +22,7 @@ import webpack from 'webpack'; import WebpackDevServer from 'webpack-dev-server'; import { paths as libPaths } from '../../lib/paths'; -import { loadCliConfig } from '../config'; +import { loadCliConfig } from '../../modules/config/lib/config'; import { createConfig, resolveBaseUrl, resolveEndpoint } from './config'; import { createDetectedModulesEntryPoint } from './packageDetection'; import { resolveBundlingPaths, resolveOptionalBundlingPaths } from './paths'; @@ -59,6 +59,26 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be let latestFrontendAppConfigs: AppConfig[] = []; + /** Triggers a full reload of all clients */ + const triggerReload = () => { + if (viteServer) { + viteServer.restart(); + } + + if (webpackServer) { + webpackServer.invalidate(); + + // For the Rspack server it's not enough to invalidate, we also need to + // tell the browser to reload, which we do with a 'static-changed' message + if (process.env.EXPERIMENTAL_RSPACK) { + webpackServer.sendMessage( + webpackServer.webSocketServer?.clients ?? [], + 'static-changed', + ); + } + } + }; + const cliConfig = await loadCliConfig({ args: options.configPaths, fromPackage: name, @@ -66,8 +86,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be watch(appConfigs) { latestFrontendAppConfigs = appConfigs; - webpackServer?.invalidate(); - viteServer?.restart(); + triggerReload(); }, }); latestFrontendAppConfigs = cliConfig.frontendAppConfigs; @@ -102,8 +121,7 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be config: fullConfig, targetPath: paths.targetPath, watch() { - webpackServer?.invalidate(); - viteServer?.restart(); + triggerReload(); }, }); @@ -215,6 +233,12 @@ DEPRECATION WARNING: React Router Beta is deprecated and support for it will be ? require('@rspack/dev-server').RspackDevServer : WebpackDevServer; + if (rspack) { + console.log( + chalk.yellow(`⚠️ WARNING: Using experimental RSPack dev server.`), + ); + } + const publicPaths = await resolveOptionalBundlingPaths({ entry: 'src/index-public-experimental', dist: 'dist/public', diff --git a/packages/cli/src/lib/lazy.ts b/packages/cli/src/lib/lazy.ts new file mode 100644 index 0000000000..6d2cb1cd4f --- /dev/null +++ b/packages/cli/src/lib/lazy.ts @@ -0,0 +1,35 @@ +/* + * 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 { assertError } from '@backstage/errors'; +import { exitWithError } from '../lib/errors'; + +// Wraps an action function so that it always exits and handles errors +export function lazy( + getActionFunc: () => Promise<(...args: any[]) => Promise>, +): (...args: any[]) => Promise { + return async (...args: any[]) => { + try { + const actionFunc = await getActionFunc(); + await actionFunc(...args); + + process.exit(0); + } catch (error) { + assertError(error); + exitWithError(error); + } + }; +} diff --git a/packages/cli/src/lib/version.test.ts b/packages/cli/src/lib/version.test.ts index 6b1aa391d5..744874d7e9 100644 --- a/packages/cli/src/lib/version.test.ts +++ b/packages/cli/src/lib/version.test.ts @@ -66,6 +66,10 @@ describe('createPackageVersionProvider', () => { expect(provider('c', '0.3.0-rc1')).toBe('0.3.0-rc1'); expect(provider('c', '0.3.0')).toBe('^0.3.0'); expect(provider('c', '0.3.6')).toBe('^0.3.4'); + + // No special handling for @types packages. + expect(provider('@types/t', '1.4.2')).toBe('^1.2.3'); + const cliVersion = packageVersions['@backstage/cli']; expect(provider('@backstage/cli')).toBe( // If we're currently in pre-release we expect that to be picked instead @@ -74,6 +78,5 @@ describe('createPackageVersionProvider', () => { expect(provider('@backstage/core-plugin-api')).toBe( `^${corePluginApiPkg.version}`, ); - expect(provider('@types/t', '1.4.2')).toBe('*'); }); }); diff --git a/packages/cli/src/lib/version.ts b/packages/cli/src/lib/version.ts index 51826ef681..f267dadfeb 100644 --- a/packages/cli/src/lib/version.ts +++ b/packages/cli/src/lib/version.ts @@ -90,12 +90,6 @@ export function createPackageVersionProvider(lockfile?: Lockfile) { } const lockfileEntries = lockfile?.get(name); - if ( - name.startsWith('@types/') && - lockfileEntries?.some(entry => entry.range === '*') - ) { - return '*'; - } for (const specifier of ['^', '~', '*']) { const range = `workspace:${specifier}`; diff --git a/packages/cli/src/modules/config/alpha.ts b/packages/cli/src/modules/config/alpha.ts new file mode 100644 index 0000000000..c32982086a --- /dev/null +++ b/packages/cli/src/modules/config/alpha.ts @@ -0,0 +1,98 @@ +/* + * 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').then(m => m.default))); + + await defaultCommand.parseAsync(args, { from: 'user' }); + }, + }); + reg.addCommand({ + path: ['config', 'docs'], + description: 'Browse the configuration reference documentation', + execute: async ({ args }) => { + const argv = await yargs + .options({ + package: { type: 'string' }, + }) + .help() + .parse(args); + const m = await import('./commands/docs'); + await m.default(argv); + }, + }); + reg.addCommand({ + path: ['config:print'], + description: 'Print the app configuration for the current package', + execute: async ({ args }) => { + 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 }, + }) + .help() + .parse(args); + const m = await 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 import('./commands/validate'); + await m.default(argv); + }, + }); + }, +}); diff --git a/packages/cli/src/commands/config/docs.ts b/packages/cli/src/modules/config/commands/docs.ts similarity index 96% rename from packages/cli/src/commands/config/docs.ts rename to packages/cli/src/modules/config/commands/docs.ts index 98e683e87c..25e3a864f4 100644 --- a/packages/cli/src/commands/config/docs.ts +++ b/packages/cli/src/modules/config/commands/docs.ts @@ -19,7 +19,7 @@ import { mergeConfigSchemas } from '@backstage/config-loader'; import { OptionValues } from 'commander'; import { JSONSchema7 as JSONSchema } from 'json-schema'; import openBrowser from 'react-dev-utils/openBrowser'; -import { loadCliConfig } from '../../lib/config'; +import { loadCliConfig } from '../lib/config'; const DOCS_URL = 'https://config.backstage.io'; diff --git a/packages/cli/src/commands/config/print.ts b/packages/cli/src/modules/config/commands/print.ts similarity index 97% rename from packages/cli/src/commands/config/print.ts rename to packages/cli/src/modules/config/commands/print.ts index 9ef725ebf8..98833a7946 100644 --- a/packages/cli/src/commands/config/print.ts +++ b/packages/cli/src/modules/config/commands/print.ts @@ -17,7 +17,7 @@ import { OptionValues } from 'commander'; import { stringify as stringifyYaml } from 'yaml'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { loadCliConfig } from '../../lib/config'; +import { loadCliConfig } from '../lib/config'; import { ConfigSchema, ConfigVisibility } from '@backstage/config-loader'; export default async (opts: OptionValues) => { diff --git a/packages/cli/src/commands/config/schema.ts b/packages/cli/src/modules/config/commands/schema.ts similarity index 97% rename from packages/cli/src/commands/config/schema.ts rename to packages/cli/src/modules/config/commands/schema.ts index 08bc46d1cc..73eb487d60 100644 --- a/packages/cli/src/commands/config/schema.ts +++ b/packages/cli/src/modules/config/commands/schema.ts @@ -17,7 +17,7 @@ import { OptionValues } from 'commander'; import { JSONSchema7 as JSONSchema } from 'json-schema'; import { stringify as stringifyYaml } from 'yaml'; -import { loadCliConfig } from '../../lib/config'; +import { loadCliConfig } from '../lib/config'; import { JsonObject } from '@backstage/types'; import { mergeConfigSchemas } from '@backstage/config-loader'; diff --git a/packages/cli/src/commands/config/validate.ts b/packages/cli/src/modules/config/commands/validate.ts similarity index 94% rename from packages/cli/src/commands/config/validate.ts rename to packages/cli/src/modules/config/commands/validate.ts index c81d82832e..ac0b9d15e0 100644 --- a/packages/cli/src/commands/config/validate.ts +++ b/packages/cli/src/modules/config/commands/validate.ts @@ -15,7 +15,7 @@ */ import { OptionValues } from 'commander'; -import { loadCliConfig } from '../../lib/config'; +import { loadCliConfig } from '../lib/config'; export default async (opts: OptionValues) => { await loadCliConfig({ diff --git a/packages/cli/src/modules/config/index.ts b/packages/cli/src/modules/config/index.ts new file mode 100644 index 0000000000..0c6a79577d --- /dev/null +++ b/packages/cli/src/modules/config/index.ts @@ -0,0 +1,87 @@ +/* + * 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 } from 'commander'; +import { lazy } from '../../lib/lazy'; + +export const configOption = [ + '--config ', + 'Config files to load instead of app-config.yaml', + (opt: string, opts: string[]) => (opts ? [...opts, opt] : [opt]), + 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').then(m => m.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').then(m => m.default))); + + 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').then(m => m.default))); + + 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').then(m => m.default))); +} diff --git a/packages/cli/src/lib/config.ts b/packages/cli/src/modules/config/lib/config.ts similarity index 99% rename from packages/cli/src/lib/config.ts rename to packages/cli/src/modules/config/lib/config.ts index aab16a8670..afed53af6f 100644 --- a/packages/cli/src/lib/config.ts +++ b/packages/cli/src/modules/config/lib/config.ts @@ -16,7 +16,7 @@ import { ConfigSources, loadConfigSchema } from '@backstage/config-loader'; import { AppConfig, ConfigReader } from '@backstage/config'; -import { paths } from './paths'; +import { paths } from '../../../lib/paths'; import { getPackages } from '@manypkg/get-packages'; import { PackageGraph } from '@backstage/cli-node'; diff --git a/packages/cli/src/wiring/CliInitializer.ts b/packages/cli/src/wiring/CliInitializer.ts new file mode 100644 index 0000000000..9fe8bb8084 --- /dev/null +++ b/packages/cli/src/wiring/CliInitializer.ts @@ -0,0 +1,138 @@ +/* + * 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 { CommandGraph } from './CommandGraph'; +import { CliFeature, InternalCliFeature, InternalCliPlugin } from './types'; +import { CommandRegistry } from './CommandRegistry'; +import { program } from 'commander'; +import { version } from '../lib/version'; +import chalk from 'chalk'; +import { exitWithError } from '../lib/errors'; +import { assertError } from '@backstage/errors'; + +type UninitializedFeature = CliFeature | Promise; + +export class CliInitializer { + private graph = new CommandGraph(); + private commandRegistry = new CommandRegistry(this.graph); + #uninitiazedFeatures: Promise[] = []; + + add(module: UninitializedFeature) { + this.#uninitiazedFeatures.push(Promise.resolve(module)); + } + + async #register(feature: CliFeature) { + if (isCliPlugin(feature)) { + await feature.init(this.commandRegistry); + } else { + throw new Error(`Unsupported feature type: ${feature.$$type}`); + } + } + + async #doInit() { + const features = await Promise.all(this.#uninitiazedFeatures); + for (const feature of features) { + await this.#register(feature); + } + } + + /** + * Actually parse argv and pass it to the command. + */ + async run() { + await this.#doInit(); + program + .name('backstage-cli') + .version(version) + .allowUnknownOption(true) + .allowExcessArguments(true); + + const queue = this.graph.atDepth(0).map(node => ({ + node, + argParser: program, + })); + while (queue.length) { + const { node, argParser } = queue.shift()!; + if (node.$$type === '@tree/root') { + const treeParser = argParser + .command(`${node.name} [command]`) + .description(node.name); + + queue.push( + ...node.children.map(child => ({ + node: child, + argParser: treeParser, + })), + ); + } else { + argParser + .command(node.name) + .description(node.command.description) + .helpOption(false) + .allowUnknownOption(true) + .allowExcessArguments(true) + .action(async () => { + try { + await node.command.execute({ + args: program.parseOptions(process.argv).unknown, + }); + process.exit(0); + } catch (error) { + assertError(error); + exitWithError(error); + } + }); + } + } + program.on('command:*', () => { + console.log(); + console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`)); + console.log(); + program.outputHelp(); + process.exit(1); + }); + + process.on('unhandledRejection', rejection => { + if (rejection instanceof Error) { + exitWithError(rejection); + } else { + exitWithError(new Error(`Unknown rejection: '${rejection}'`)); + } + }); + + program.parse(process.argv); + } +} + +function toInternalCliFeature(feature: CliFeature): InternalCliFeature { + if (feature.$$type !== '@backstage/CliFeature') { + throw new Error(`Invalid CliFeature, bad type '${feature.$$type}'`); + } + const internal = feature as InternalCliFeature; + if (internal.version !== 'v1') { + throw new Error(`Invalid CliFeature, bad version '${internal.version}'`); + } + return internal; +} + +function isCliPlugin(feature: CliFeature): feature is InternalCliPlugin { + const internal = toInternalCliFeature(feature); + if (internal.featureType === 'plugin') { + return true; + } + // Backwards compatibility for v1 registrations that use duck typing + return 'plugin' in internal; +} diff --git a/packages/cli/src/wiring/CommandGraph.ts b/packages/cli/src/wiring/CommandGraph.ts new file mode 100644 index 0000000000..a0a2de3305 --- /dev/null +++ b/packages/cli/src/wiring/CommandGraph.ts @@ -0,0 +1,103 @@ +/* + * 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 { BackstageCommand } from './types'; + +type Node = TreeNode | LeafNode; + +interface TreeNode { + $$type: '@tree/root'; + name: string; + children: TreeNode[]; +} + +interface LeafNode { + $$type: '@tree/leaf'; + name: string; + command: BackstageCommand; +} + +/** + * A sparse graph of commands. + */ +export class CommandGraph { + private graph: Node[] = []; + + /** + * Adds a command to the graph. The graph is sparse, so we use the path to determine the nodes + * to traverse. Only leaf nodes should have a command/action. + */ + add(command: BackstageCommand) { + const path = command.path; + let current = this.graph; + for (let i = 0; i < path.length - 1; i++) { + const name = path[i]; + let next = current.find(n => n.name === name); + if (!next) { + next = { $$type: '@tree/root', name, children: [] }; + current.push(next); + } else if (next.$$type === '@tree/leaf') { + throw new Error( + `Command already exists at path: "${path.slice(0, i).join(' ')}"`, + ); + } + current = next.children; + } + const last = current.find(n => n.name === path[path.length - 1]); + if (last && last.$$type === '@tree/leaf') { + throw new Error( + `Command already exists at path: "${path.slice(0, -1).join(' ')}"`, + ); + } else { + current.push({ + $$type: '@tree/leaf', + name: path[path.length - 1], + command, + }); + } + } + + /** + * Given a path, try to find a command that matches it. + */ + find(path: string[]): BackstageCommand | undefined { + let current = this.graph; + for (let i = 0; i < path.length - 1; i++) { + const name = path[i]; + const next = current.find(n => n.name === name); + if (!next) { + return undefined; + } else if (next.$$type === '@tree/leaf') { + return undefined; + } + current = next.children; + } + const last = current.find(n => n.name === path[path.length - 1]); + if (!last || last.$$type === '@tree/root') { + return undefined; + } + return last?.command; + } + + atDepth(depth: number): Node[] { + let current = this.graph; + for (let i = 0; i < depth; i++) { + current = current.flatMap(n => + n.$$type === '@tree/root' ? n.children : [], + ); + } + return current; + } +} diff --git a/packages/cli/src/wiring/CommandRegistry.ts b/packages/cli/src/wiring/CommandRegistry.ts new file mode 100644 index 0000000000..9e8ff9646c --- /dev/null +++ b/packages/cli/src/wiring/CommandRegistry.ts @@ -0,0 +1,28 @@ +/* + * 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 { CommandGraph } from './CommandGraph'; +import { BackstageCommand } from './types'; + +export class CommandRegistry { + private graph: CommandGraph; + constructor(graph: CommandGraph) { + this.graph = graph; + } + + addCommand(command: BackstageCommand) { + this.graph.add(command); + } +} diff --git a/packages/cli/src/wiring/factory.ts b/packages/cli/src/wiring/factory.ts new file mode 100644 index 0000000000..eec058e180 --- /dev/null +++ b/packages/cli/src/wiring/factory.ts @@ -0,0 +1,32 @@ +/* + * 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 { CommandRegistry } from './CommandRegistry'; +import { InternalCliPlugin } from './types'; + +export function createCliPlugin(options: { + pluginId: string; + init: (registry: CommandRegistry) => Promise; +}): InternalCliPlugin { + return { + id: options.pluginId, + init: options.init, + $$type: '@backstage/CliFeature', + version: 'v1', + featureType: 'plugin', + description: 'A Backstage CLI plugin', + }; +} diff --git a/packages/cli/src/wiring/types.ts b/packages/cli/src/wiring/types.ts new file mode 100644 index 0000000000..d9237a4c3a --- /dev/null +++ b/packages/cli/src/wiring/types.ts @@ -0,0 +1,46 @@ +/* + * 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 { CommandRegistry } from './CommandRegistry'; + +export interface BackstageCommand { + path: string[]; + description: string; + execute: (options: { args: string[] }) => Promise; +} + +export interface CliFeature { + $$type: '@backstage/CliFeature'; +} + +export interface CliPlugin { + id: string; + init: (registry: CommandRegistry) => Promise; + $$type: '@backstage/CliFeature'; +} + +/** + * @public + */ +export interface InternalCliPlugin extends CliFeature { + version: 'v1'; + featureType: 'plugin'; + description: string; + id: string; + init: (registry: CommandRegistry) => Promise; +} + +/** @internal */ +export type InternalCliFeature = InternalCliPlugin; diff --git a/packages/codemods/CHANGELOG.md b/packages/codemods/CHANGELOG.md index 99bdd90002..89c2f0ecfa 100644 --- a/packages/codemods/CHANGELOG.md +++ b/packages/codemods/CHANGELOG.md @@ -1,5 +1,13 @@ # @backstage/codemods +## 0.1.52 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.15 + ## 0.1.52-next.0 ### Patch Changes diff --git a/packages/codemods/package.json b/packages/codemods/package.json index 3a188de891..92b3dc7042 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/codemods", - "version": "0.1.52-next.0", + "version": "0.1.52", "description": "A collection of codemods for Backstage projects", "backstage": { "role": "cli" diff --git a/packages/config-loader/CHANGELOG.md b/packages/config-loader/CHANGELOG.md index 8dbf62734e..15548ca9d7 100644 --- a/packages/config-loader/CHANGELOG.md +++ b/packages/config-loader/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/config-loader +## 1.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 1.9.3-next.0 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 1.9.2 + +### Patch Changes + +- c5e39e7: Internal refactor to use the deferred from the types package +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + ## 1.9.2-next.0 ### Patch Changes diff --git a/packages/config-loader/package.json b/packages/config-loader/package.json index 1f9558794b..3359e285d9 100644 --- a/packages/config-loader/package.json +++ b/packages/config-loader/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config-loader", - "version": "1.9.2-next.0", + "version": "1.9.3-next.1", "description": "Config loading functionality used by Backstage backend, and CLI", "backstage": { "role": "node-library" @@ -49,7 +49,6 @@ "json-schema-traverse": "^1.0.0", "lodash": "^4.17.21", "minimist": "^1.2.5", - "node-fetch": "^2.7.0", "typescript-json-schema": "^0.65.0", "yaml": "^2.0.0" }, diff --git a/packages/config-loader/src/sources/RemoteConfigSource.ts b/packages/config-loader/src/sources/RemoteConfigSource.ts index 1492cd4d28..d8fa07d708 100644 --- a/packages/config-loader/src/sources/RemoteConfigSource.ts +++ b/packages/config-loader/src/sources/RemoteConfigSource.ts @@ -21,7 +21,6 @@ import { durationToMilliseconds, } from '@backstage/types'; import isEqual from 'lodash/isEqual'; -import fetch from 'node-fetch'; import { ConfigTransformer, createConfigTransformer } from './transform'; import { AsyncConfigSourceGenerator, @@ -137,7 +136,7 @@ export class RemoteConfigSource implements ConfigSource { async #load(signal?: AbortSignal): Promise { const res = await fetch(this.#url, { - signal: signal as import('node-fetch').RequestInit['signal'], + signal: signal as RequestInit['signal'], }); if (!res.ok) { throw await ResponseError.fromResponse(res); diff --git a/packages/config-loader/src/sources/types.ts b/packages/config-loader/src/sources/types.ts index abdf2f5c8e..fedce213c5 100644 --- a/packages/config-loader/src/sources/types.ts +++ b/packages/config-loader/src/sources/types.ts @@ -39,7 +39,7 @@ export interface ReadConfigDataOptions { } /** - * The the generator returned by {@link ConfigSource.readConfigData}. + * The generator returned by {@link ConfigSource.readConfigData}. * * @public */ diff --git a/packages/config/CHANGELOG.md b/packages/config/CHANGELOG.md index 43cc91fd34..f4f0429f8e 100644 --- a/packages/config/CHANGELOG.md +++ b/packages/config/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/config +## 1.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## 1.3.0 + +### Minor Changes + +- d52d7f9: Make `readDurationFromConfig` support both ISO and ms formats as well, to make it easier to enter time as an end user + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + ## 1.2.0 ### Minor Changes diff --git a/packages/config/package.json b/packages/config/package.json index 35bc0719e3..79a2dfe980 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/config", - "version": "1.2.0", + "version": "1.3.1-next.0", "description": "Config API used by Backstage core, backend, and CLI", "backstage": { "role": "common-library" @@ -37,7 +37,8 @@ }, "dependencies": { "@backstage/errors": "workspace:^", - "@backstage/types": "workspace:^" + "@backstage/types": "workspace:^", + "ms": "^2.1.3" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/packages/config/src/readDurationFromConfig.test.ts b/packages/config/src/readDurationFromConfig.test.ts index 3da790ddcf..f3fa0819b0 100644 --- a/packages/config/src/readDurationFromConfig.test.ts +++ b/packages/config/src/readDurationFromConfig.test.ts @@ -15,114 +15,254 @@ */ import { - readDurationFromConfig, propsOfHumanDuration, + readDurationFromConfig, } from './readDurationFromConfig'; import { ConfigReader } from './reader'; describe('readDurationFromConfig', () => { - it('reads all known keys', () => { - const config = new ConfigReader({ - milliseconds: 1, - seconds: 2, - minutes: 3, - hours: 4, - days: 5, - weeks: 6, - months: 7, - years: 8, + describe('ISO form', () => { + it('parses the known forms', () => { + const config = new ConfigReader({ + d1: 'P2DT6H', + d2: 'PT0.5S', + d3: 'PT3.1S', + d4: 'P1Y2M3W4DT5H6M7.8S', + }); + + expect(readDurationFromConfig(config, { key: 'd1' })).toEqual({ + days: 2, + hours: 6, + }); + expect(readDurationFromConfig(config, { key: 'd2' })).toEqual({ + milliseconds: 500, + }); + expect(readDurationFromConfig(config, { key: 'd3' })).toEqual({ + seconds: 3, + milliseconds: 100, + }); + expect(readDurationFromConfig(config, { key: 'd4' })).toEqual({ + years: 1, + months: 2, + weeks: 3, + days: 4, + hours: 5, + minutes: 6, + seconds: 7, + milliseconds: 800, + }); }); - expect(readDurationFromConfig(config)).toEqual({ - milliseconds: 1, - seconds: 2, - minutes: 3, - hours: 4, - days: 5, - weeks: 6, - months: 7, - years: 8, + + it('throws on errors', () => { + const config = new ConfigReader({ + d1: 'P 1Y', + d2: 'P1L', + d3: 'P', + }); + + expect(() => + readDurationFromConfig(config, { key: 'd1' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration 'P 1Y' in config at 'd1', Error: Invalid ISO format, expected a value similar to 'P2DT6H' (2 days 6 hours) or 'PT1M' (1 minute)"`, + ); + expect(() => + readDurationFromConfig(config, { key: 'd2' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration 'P1L' in config at 'd2', Error: Invalid ISO format, expected a value similar to 'P2DT6H' (2 days 6 hours) or 'PT1M' (1 minute)"`, + ); + expect(() => + readDurationFromConfig(config, { key: 'd3' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration 'P' in config at 'd3', Error: Invalid ISO format, no values given"`, + ); }); }); - it('reads all known keys, for a subkey', () => { - const config = new ConfigReader({ - sub: { - key: { - milliseconds: 1, - seconds: 2, - minutes: 3, - hours: 4, - days: 5, - weeks: 6, - months: 7, - years: 8, + describe('ms form', () => { + it('parses the known units', () => { + // this is not exhaustive, but tests all supported units to ensure that + // our conversion to HumanDuration form works + const config = new ConfigReader({ + d1: '1y', + d2: '2 years', + d3: '4w', + d4: '5h', + d5: '6 hrs', + d6: '7min', + d7: '9 minutes', + d8: '3.5 seconds', + d9: '25 ms', + d10: '1850ms', + }); + + expect(readDurationFromConfig(config, { key: 'd1' })).toEqual({ + years: 1, + }); + expect(readDurationFromConfig(config, { key: 'd2' })).toEqual({ + years: 2, + }); + expect(readDurationFromConfig(config, { key: 'd3' })).toEqual({ + weeks: 4, + }); + expect(readDurationFromConfig(config, { key: 'd4' })).toEqual({ + hours: 5, + }); + expect(readDurationFromConfig(config, { key: 'd5' })).toEqual({ + hours: 6, + }); + expect(readDurationFromConfig(config, { key: 'd6' })).toEqual({ + minutes: 7, + }); + expect(readDurationFromConfig(config, { key: 'd7' })).toEqual({ + minutes: 9, + }); + expect(readDurationFromConfig(config, { key: 'd8' })).toEqual({ + seconds: 3, + milliseconds: 500, + }); + expect(readDurationFromConfig(config, { key: 'd9' })).toEqual({ + milliseconds: 25, + }); + expect(readDurationFromConfig(config, { key: 'd10' })).toEqual({ + seconds: 1, + milliseconds: 850, + }); + }); + + it('throws on errors', () => { + const config = new ConfigReader({ + d1: '1m 3s', + d2: '-3s', + d3: '', + }); + + expect(() => + readDurationFromConfig(config, { key: 'd1' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration '1m 3s' in config at 'd1', Error: Not a valid duration string, try a number followed by a unit such as '1d' or '2 seconds'"`, + ); + expect(() => + readDurationFromConfig(config, { key: 'd2' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid duration '-3s' in config at 'd2', Error: Negative durations are not allowed"`, + ); + expect(() => + readDurationFromConfig(config, { key: 'd3' }), + ).toThrowErrorMatchingInlineSnapshot( + `"Invalid type in config for key 'd3' in 'mock-config', got empty-string, wanted string"`, + ); + }); + }); + + describe('object form', () => { + it('reads all known keys', () => { + const config = new ConfigReader({ + milliseconds: 1, + seconds: 2, + minutes: 3, + hours: 4, + days: 5, + weeks: 6, + months: 7, + years: 8, + }); + expect(readDurationFromConfig(config)).toEqual({ + milliseconds: 1, + seconds: 2, + minutes: 3, + hours: 4, + days: 5, + weeks: 6, + months: 7, + years: 8, + }); + }); + + it('reads all known keys, for a subkey', () => { + const config = new ConfigReader({ + sub: { + key: { + milliseconds: 1, + seconds: 2, + minutes: 3, + hours: 4, + days: 5, + weeks: 6, + months: 7, + years: 8, + }, }, + }); + expect(readDurationFromConfig(config, { key: 'sub.key' })).toEqual({ + milliseconds: 1, + seconds: 2, + minutes: 3, + hours: 4, + days: 5, + weeks: 6, + months: 7, + years: 8, + }); + }); + + it('rejects wrong type of target, for a subkey', () => { + const config = new ConfigReader({ + sub: { key: 7 }, + }); + expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow( + "Failed to read duration from config, TypeError: Invalid type in config for key 'sub.key' in 'mock-config', got number, wanted object", + ); + }); + + it('rejects no keys', () => { + const config = new ConfigReader({}); + expect(() => readDurationFromConfig(config)).toThrow( + `Failed to read duration from config, Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, + ); + }); + + it('rejects no keys, for a subkey', () => { + const config = new ConfigReader({ sub: { key: {} } }); + expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow( + `Failed to read duration from config at 'sub.key', Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, + ); + }); + + it('rejects unknown keys', () => { + const config = new ConfigReader({ + minutes: 3, + invalid: 'value', + }); + expect(() => readDurationFromConfig(config)).toThrow( + `Failed to read duration from config, Error: Unknown property 'invalid'; expected one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, + ); + }); + + it.each(propsOfHumanDuration)('rejects non-number %p', prop => { + const config = new ConfigReader({ + [prop]: 'value', + }); + expect(() => readDurationFromConfig(config)).toThrow( + `Failed to read duration from config, Error: Unable to convert config value for key '${prop}' in 'mock-config' to a number`, + ); + }); + + it.each(propsOfHumanDuration)( + 'rejects non-number %p, for a subkey', + prop => { + const config = new ConfigReader({ + sub: { + key: { + [prop]: 'value', + }, + }, + }); + expect(() => + readDurationFromConfig(config, { key: 'sub.key' }), + ).toThrow( + `Failed to read duration from config, Error: Unable to convert config value for key 'sub.key.${prop}' in 'mock-config' to a number`, + ); }, - }); - expect(readDurationFromConfig(config, { key: 'sub.key' })).toEqual({ - milliseconds: 1, - seconds: 2, - minutes: 3, - hours: 4, - days: 5, - weeks: 6, - months: 7, - years: 8, - }); - }); - - it('rejects wrong type of target, for a subkey', () => { - const config = new ConfigReader({ - sub: { key: 7 }, - }); - expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow( - "Failed to read duration from config, TypeError: Invalid type in config for key 'sub.key' in 'mock-config', got number, wanted object", - ); - }); - - it('rejects no keys', () => { - const config = new ConfigReader({}); - expect(() => readDurationFromConfig(config)).toThrow( - `Failed to read duration from config, Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, - ); - }); - - it('rejects no keys, for a subkey', () => { - const config = new ConfigReader({ sub: { key: {} } }); - expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow( - `Failed to read duration from config at 'sub.key', Error: Needs one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, - ); - }); - - it('rejects unknown keys', () => { - const config = new ConfigReader({ - minutes: 3, - invalid: 'value', - }); - expect(() => readDurationFromConfig(config)).toThrow( - `Failed to read duration from config, Error: Unknown property 'invalid'; expected one or more of 'years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds', 'milliseconds'`, - ); - }); - - it.each(propsOfHumanDuration)('rejects non-number %p', prop => { - const config = new ConfigReader({ - [prop]: 'value', - }); - expect(() => readDurationFromConfig(config)).toThrow( - `Failed to read duration from config, Error: Unable to convert config value for key '${prop}' in 'mock-config' to a number`, - ); - }); - - it.each(propsOfHumanDuration)('rejects non-number %p, for a subkey', prop => { - const config = new ConfigReader({ - sub: { - key: { - [prop]: 'value', - }, - }, - }); - expect(() => readDurationFromConfig(config, { key: 'sub.key' })).toThrow( - `Failed to read duration from config, Error: Unable to convert config value for key 'sub.key.${prop}' in 'mock-config' to a number`, ); }); }); diff --git a/packages/config/src/readDurationFromConfig.ts b/packages/config/src/readDurationFromConfig.ts index 2f59e9a976..e02651084e 100644 --- a/packages/config/src/readDurationFromConfig.ts +++ b/packages/config/src/readDurationFromConfig.ts @@ -15,8 +15,9 @@ */ import { Config } from '@backstage/config'; -import { InputError } from '@backstage/errors'; +import { InputError, stringifyError } from '@backstage/errors'; import { HumanDuration } from '@backstage/types'; +import ms from 'ms'; export const propsOfHumanDuration = [ 'years', @@ -30,18 +31,29 @@ export const propsOfHumanDuration = [ ]; /** - * Reads a duration from a config object. + * Reads a duration from config. * * @public * @remarks * + * The supported formats are: + * + * - 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 }`. + * + * The string forms are naturally only supported if the `options.key` argument + * is passed, since a `Config` argument always represents an object by its + * nature. + * * This does not support optionality; if you want to support optional durations, * you need to first check the presence of the target with `config.has(...)` and * then call this function. * * @param config - A configuration object - * @param key - If specified, read the duration from the given subkey - * under the config object + * @param key - If specified, read the duration from the given subkey under the + * config object * @returns A duration object */ export function readDurationFromConfig( @@ -49,6 +61,33 @@ export function readDurationFromConfig( options?: { key?: string; }, +): HumanDuration { + if (options?.key && typeof config.getOptional(options.key) === 'string') { + const value = config.getString(options.key).trim(); + try { + return value.startsWith('P') + ? parseIsoDuration(value) + : parseMsDuration(value); + } catch (error) { + throw new InputError( + `Invalid duration '${value}' in config at '${ + options.key + }', ${stringifyError(error)}`, + ); + } + } + + return parseObjectDuration(config, options); +} + +/** + * Parses the object form of durations. + */ +export function parseObjectDuration( + config: Config, + options?: { + key?: string; + }, ): HumanDuration { let root: Config; let found = false; @@ -94,8 +133,178 @@ export function readDurationFromConfig( if (options?.key) { prefix += ` at '${options.key}'`; } - throw new InputError(`${prefix}, ${error}`); + throw new Error(`${prefix}, ${error}`); } return result as HumanDuration; } + +/** + * Parses friendly string durations like '1d', '2 seconds' etc using the ms + * library. + */ +export function parseMsDuration(input: string): HumanDuration { + if (/^\d+$/.exec(input)) { + // We explicitly disallow the only-digits form of the ms library, because + // from a configuration perspective it's just confusing to even be able to + // specify that + throw new Error( + `The value cannot be a plain number; try adding a unit like 'ms' or 'seconds'`, + ); + } + + let milliseconds = ms(input); + if (!Number.isFinite(milliseconds)) { + throw new Error( + `Not a valid duration string, try a number followed by a unit such as '1d' or '2 seconds'`, + ); + } else if (milliseconds < 0) { + throw new Error('Negative durations are not allowed'); + } else if (milliseconds === 0) { + return { milliseconds: 0 }; + } + + // As used by the ms library + const s = 1000; + const m = s * 60; + const h = m * 60; + const d = h * 24; + const w = d * 7; + const y = d * 365.25; + + const result: HumanDuration = {}; + + if (milliseconds >= y) { + const years = Math.floor(milliseconds / y); + milliseconds -= years * y; + result.years = years; + } + + if (milliseconds >= w) { + const weeks = Math.floor(milliseconds / w); + milliseconds -= weeks * w; + result.weeks = weeks; + } + + if (milliseconds >= d) { + const days = Math.floor(milliseconds / d); + milliseconds -= days * d; + result.days = days; + } + + if (milliseconds >= h) { + const hours = Math.floor(milliseconds / h); + milliseconds -= hours * h; + result.hours = hours; + } + + if (milliseconds >= m) { + const minutes = Math.floor(milliseconds / m); + milliseconds -= minutes * m; + result.minutes = minutes; + } + + if (milliseconds >= s) { + const seconds = Math.floor(milliseconds / s); + milliseconds -= seconds * s; + result.seconds = seconds; + } + + if (milliseconds > 0) { + result.milliseconds = milliseconds; + } + + return result; +} + +/** + * Parses an ISO formatted duration string. + * + * Implementation taken from luxon's Duration.fromISO to not force that + * dependency on everyone. + */ +export function parseIsoDuration(input: string): HumanDuration { + const match = + /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/.exec( + input, + ); + if (!match) { + throw new Error( + `Invalid ISO format, expected a value similar to 'P2DT6H' (2 days 6 hours) or 'PT1M' (1 minute)`, + ); + } + + const [ + s, + yearStr, + monthStr, + weekStr, + dayStr, + hourStr, + minuteStr, + secondStr, + millisecondsStr, + ] = match; + + const hasNegativePrefix = s[0] === '-'; + const negativeSeconds = !!secondStr && secondStr[0] === '-'; + + const maybeNegate = (num: number | undefined, force = false) => + num !== undefined && (force || (num && hasNegativePrefix)) ? -num : num; + + const parseFloating = (value: string) => { + if (typeof value === 'undefined' || value === null || value === '') { + return undefined; + } + return parseFloat(value); + }; + + const parseMillis = (fraction: string | undefined) => { + // Return undefined (instead of 0) in these cases, where fraction is not set + if ( + typeof fraction === 'undefined' || + fraction === null || + fraction === '' + ) { + return undefined; + } + const f = parseFloat(`0.${fraction}`) * 1000; + return Math.floor(f); + }; + + const years = maybeNegate(parseFloating(yearStr)); + const months = maybeNegate(parseFloating(monthStr)); + const weeks = maybeNegate(parseFloating(weekStr)); + const days = maybeNegate(parseFloating(dayStr)); + const hours = maybeNegate(parseFloating(hourStr)); + const minutes = maybeNegate(parseFloating(minuteStr)); + const seconds = maybeNegate(parseFloating(secondStr), secondStr === '-0'); + const milliseconds = maybeNegate( + parseMillis(millisecondsStr), + negativeSeconds, + ); + + if ( + years === undefined && + months === undefined && + weeks === undefined && + days === undefined && + hours === undefined && + minutes === undefined && + seconds === undefined && + milliseconds === undefined + ) { + throw new Error('Invalid ISO format, no values given'); + } + + return { + ...(years ? { years } : {}), + ...(months ? { months } : {}), + ...(weeks ? { weeks } : {}), + ...(days ? { days } : {}), + ...(hours ? { hours } : {}), + ...(minutes ? { minutes } : {}), + ...(seconds ? { seconds } : {}), + ...(milliseconds ? { milliseconds } : {}), + }; +} diff --git a/packages/core-app-api/CHANGELOG.md b/packages/core-app-api/CHANGELOG.md index d5836eb341..995d8140f7 100644 --- a/packages/core-app-api/CHANGELOG.md +++ b/packages/core-app-api/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/core-app-api +## 1.15.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 1.15.3-next.0 + +### Patch Changes + +- e5fa018: The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes. +- 2830689: Decrease OAuth2 token refresh grace period +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 1.15.2 + +### Patch Changes + +- 44b82da: The default config loader no longer requires `process.env.APP_CONFIG` to be set, allowing config to be read from other sources instead. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + ## 1.15.1 ### Patch Changes diff --git a/packages/core-app-api/package.json b/packages/core-app-api/package.json index 88edc6ccfd..92bf422050 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.15.1", + "version": "1.15.3-next.1", "description": "Core app API used by Backstage apps", "backstage": { "role": "web-library" diff --git a/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.ts b/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.ts index 58ffc9441b..37b50bdcbb 100644 --- a/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.ts +++ b/packages/core-app-api/src/apis/implementations/DiscoveryApi/UrlPatternDiscovery.ts @@ -26,7 +26,7 @@ const ERROR_PREFIX = 'Invalid discovery URL pattern,'; */ export class UrlPatternDiscovery implements DiscoveryApi { /** - * Creates a new UrlPatternDiscovery given a template. The the only + * Creates a new UrlPatternDiscovery given a template. The only * interpolation done for the template is to replace instances of `{{pluginId}}` * with the ID of the plugin being requested. * diff --git a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts index dbad031652..4963330724 100644 --- a/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts +++ b/packages/core-app-api/src/apis/implementations/auth/oauth2/OAuth2.ts @@ -148,7 +148,7 @@ export default class OAuth2 (session.backstageIdentity.expiresAt.getTime() - Date.now()) / 1000, ); } - return min < 60 * 5; + return min < 60 * 3; }, }); diff --git a/packages/core-app-api/src/app/defaultConfigLoader.test.tsx b/packages/core-app-api/src/app/defaultConfigLoader.test.tsx index 44d93aa625..556e4c928e 100644 --- a/packages/core-app-api/src/app/defaultConfigLoader.test.tsx +++ b/packages/core-app-api/src/app/defaultConfigLoader.test.tsx @@ -29,6 +29,10 @@ describe('defaultConfigLoaderSync', () => { delete anyWindow.__APP_CONFIG__; }); + it('loads nothing is config is missing', () => { + expect(defaultConfigLoaderSync()).toEqual([]); + }); + it('loads static config', () => { anyEnv.APP_CONFIG = [ { data: { my: 'config' }, context: 'a' }, @@ -95,12 +99,6 @@ describe('defaultConfigLoaderSync', () => { expect(ConfigReader.fromConfigs(configs).get('my')).toBe('override-config'); }); - it('fails to load invalid missing config', () => { - expect(() => defaultConfigLoaderSync()).toThrow( - 'No static configuration provided', - ); - }); - it('fails to load invalid static config', () => { anyEnv.APP_CONFIG = { my: 'invalid-config' }; expect(() => defaultConfigLoaderSync()).toThrow( diff --git a/packages/core-app-api/src/app/defaultConfigLoader.ts b/packages/core-app-api/src/app/defaultConfigLoader.ts index bfcef390ec..0a65112041 100644 --- a/packages/core-app-api/src/app/defaultConfigLoader.ts +++ b/packages/core-app-api/src/app/defaultConfigLoader.ts @@ -40,14 +40,15 @@ export function defaultConfigLoaderSync( // It's a param so we can test it, but at runtime this will always fall back to default. runtimeConfigJson: string = '__APP_INJECTED_RUNTIME_CONFIG__', ) { - const appConfig = process.env.APP_CONFIG; - if (!appConfig) { - throw new Error('No static configuration provided'); + const configs = new Array(); + + const staticConfig = process.env.APP_CONFIG; + if (staticConfig) { + if (!Array.isArray(staticConfig)) { + throw new Error('Static configuration has invalid format'); + } + configs.push(...staticConfig); } - if (!Array.isArray(appConfig)) { - throw new Error('Static configuration has invalid format'); - } - const configs = appConfig.slice() as unknown as AppConfig[]; // Check if we have any config script tags, otherwise fall back to injected config const configScripts = document.querySelectorAll( diff --git a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.test.ts b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.test.ts index e26934f393..88000638e6 100644 --- a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.test.ts +++ b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.test.ts @@ -165,4 +165,107 @@ describe('RefreshingAuthSessionManager', () => { expect(removeSession).toHaveBeenCalled(); expect(await manager.getSession({ optional: true })).toBe(undefined); }); + + it('should handle two simultaneous session refreshes with same scopes', async () => { + const createSession = jest.fn(); + const refreshSession = jest.fn(async (scopes?: Set) => ({ + scopes: scopes ?? new Set(), + expired: false, + })); + const manager = new RefreshingAuthSessionManager({ + connector: { createSession, refreshSession }, + ...defaultOptions, + } as any); + + const sessionPromise1 = manager.getSession({ scopes: new Set(['a']) }); + const sessionPromise2 = manager.getSession({ scopes: new Set(['a']) }); + + const [session1, session2] = await Promise.all([ + sessionPromise1, + sessionPromise2, + ]); + + expect(session1).toEqual({ scopes: new Set(['a']), expired: false }); + expect(session2).toEqual({ scopes: new Set(['a']), expired: false }); + expect(refreshSession).toHaveBeenCalledTimes(1); + }); + + it('should handle two simultaneous session refreshes with different scopes', async () => { + const createSession = jest.fn(); + const refreshSession = jest.fn(async (scopes?: Set) => ({ + scopes: scopes ?? new Set(), + expired: false, + })); + const manager = new RefreshingAuthSessionManager({ + connector: { createSession, refreshSession }, + ...defaultOptions, + } as any); + + const sessionPromise1 = manager.getSession({ scopes: new Set(['a']) }); + const sessionPromise2 = manager.getSession({ scopes: new Set(['b']) }); + + const [session1, session2] = await Promise.all([ + sessionPromise1, + sessionPromise2, + ]); + + expect(session1).toEqual({ scopes: new Set(['a']), expired: false }); + expect(session2).toEqual({ scopes: new Set(['a', 'b']), expired: false }); + expect(refreshSession).toHaveBeenCalledTimes(2); + }); + + it('should handle multiple simultaneous session refreshes with different scopes', async () => { + const createSession = jest.fn(); + const refreshSession = jest.fn(async (scopes?: Set) => ({ + scopes: scopes ?? new Set(), + expired: false, + })); + const manager = new RefreshingAuthSessionManager({ + connector: { createSession, refreshSession }, + ...defaultOptions, + } as any); + + const sessionPromise1 = manager.getSession({ scopes: new Set(['a']) }); + const sessionPromise2 = manager.getSession({ scopes: new Set(['a', 'b']) }); + const sessionPromise3 = manager.getSession({ scopes: new Set(['b', 'c']) }); + const sessionPromise4 = manager.getSession({ scopes: new Set(['a', 'c']) }); + + const [session1, session2, session3, session4] = await Promise.all([ + sessionPromise1, + sessionPromise2, + sessionPromise3, + sessionPromise4, + ]); + + expect(session1).toEqual({ scopes: new Set(['a']), expired: false }); + expect(session2).toEqual({ scopes: new Set(['a', 'b']), expired: false }); + expect(session3).toEqual({ + scopes: new Set(['a', 'b', 'c']), + expired: false, + }); + expect(session4).toEqual({ + scopes: new Set(['a', 'b', 'c']), + expired: false, + }); + expect(refreshSession).toHaveBeenCalledTimes(3); + }); + + it("should fall back to create a new session if refresh doesn't provide the correct scopes", async () => { + const createSession = jest + .fn() + .mockResolvedValue({ scopes: new Set(['c']), expired: false }); + const refreshSession = jest + .fn() + .mockResolvedValue({ scopes: new Set(['b']), expired: false }); + const manager = new RefreshingAuthSessionManager({ + connector: { createSession, refreshSession }, + ...defaultOptions, + } as any); + + const session = await manager.getSession({ scopes: new Set(['a']) }); + + expect(session).toEqual({ scopes: new Set(['c']), expired: false }); + expect(refreshSession).toHaveBeenCalledTimes(1); + expect(createSession).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts index c92fe9fb20..414743ba9d 100644 --- a/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts +++ b/packages/core-app-api/src/lib/AuthSessionManager/RefreshingAuthSessionManager.ts @@ -97,7 +97,7 @@ export class RefreshingAuthSessionManager implements SessionManager { // stay in a synchronous call stack from the user interaction. The downside // is that the user will sometimes be requested to log in even if they // already had an existing session. - if (!this.currentSession && !options.instantPopup) { + if (!options.instantPopup) { try { const newSession = await this.collapsedSessionRefresh(options.scopes); this.currentSession = newSession; @@ -143,6 +143,11 @@ export class RefreshingAuthSessionManager implements SessionManager { try { const session = await this.refreshPromise; + if (!this.helper.sessionExistsAndHasScope(session, scopes)) { + throw new Error( + 'Refreshed session did not receive the required scopes', + ); + } this.stateTracker.setIsSignedIn(true); return session; } finally { diff --git a/packages/core-compat-api/CHANGELOG.md b/packages/core-compat-api/CHANGELOG.md index 029e6840cb..e8fd9439d0 100644 --- a/packages/core-compat-api/CHANGELOG.md +++ b/packages/core-compat-api/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/core-compat-api +## 0.3.4-next.2 + +### Patch Changes + +- 1f30730: Updated dependency `@oriflame/backstage-plugin-score-card` to `^0.9.0`. +- Updated dependencies + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/version-bridge@1.0.10 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/version-bridge@1.0.10 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + ## 0.3.2-next.2 ### Patch Changes diff --git a/packages/core-compat-api/package.json b/packages/core-compat-api/package.json index b33931706b..83d0d2ee51 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.3.2-next.2", + "version": "0.3.4-next.2", "backstage": { "role": "web-library" }, @@ -46,7 +46,7 @@ "@backstage/plugin-catalog": "workspace:^", "@backstage/test-utils": "workspace:^", "@backstage/types": "workspace:^", - "@oriflame/backstage-plugin-score-card": "^0.8.0", + "@oriflame/backstage-plugin-score-card": "^0.9.0", "@testing-library/jest-dom": "^6.0.0", "@testing-library/react": "^16.0.0", "@types/react": "^18.0.0", diff --git a/packages/core-components/CHANGELOG.md b/packages/core-components/CHANGELOG.md index ed125d815a..37c3b72d7e 100644 --- a/packages/core-components/CHANGELOG.md +++ b/packages/core-components/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/core-components +## 0.16.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/version-bridge@1.0.10 + +## 0.16.2-next.1 + +### Patch Changes + +- e47be38: Added data-testid to placeholder rendered by Progress component to simplify assertions in tests +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/theme@0.6.3-next.0 + - @backstage/version-bridge@1.0.10 + +## 0.16.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + +## 0.16.0 + +### Minor Changes + +- dc409c5: The SupportButton component will now be hidden if no support config is specified in app-config + +### Patch Changes + +- 0f18340: Change core component Table tool bar search box to the a appropriate Search icon and text +- af9097e: Adds the ability to mock a media query per break point and to change the active break point during a test. Usage example: + + ```ts + const { set } = mockBreakpoint({ + initialBreakpoint: 'md', + queryBreakpointMap: { + '(min-width:1500px)': 'xl', + '(min-width:1000px)': 'lg', + '(min-width:700px)': 'md', + '(min-width:400px)': 'sm', + '(min-width:0px)': 'xs', + }, + }); + // assertions for when the active break point is "md" + set('lg'); + // assertions for when the active break point is "lg" + ``` + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + ## 0.16.0-next.2 ### Patch Changes diff --git a/packages/core-components/package.json b/packages/core-components/package.json index c4bc3d7b6a..6405e49836 100644 --- a/packages/core-components/package.json +++ b/packages/core-components/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/core-components", - "version": "0.16.0-next.2", + "version": "0.16.2-next.2", "description": "Core components used by Backstage plugins and apps", "backstage": { "role": "web-library" diff --git a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx index d9d82437e4..21b576dd9f 100644 --- a/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx +++ b/packages/core-components/src/components/MarkdownContent/MarkdownContent.test.tsx @@ -120,6 +120,23 @@ describe('', () => { ); }); + it('render MarkdownContent component with link target set to _blank', async () => { + await renderInTestApp( + , + ); + const readme = screen.getByText('README', { + selector: 'a', + }); + expect(readme).toBeInTheDocument(); + expect(readme.getAttribute('href')).toEqual( + 'https://github.com/backstage/backstage/blob/master/README.md', + ); + expect(readme.getAttribute('target')).toEqual('_blank'); + }); + it('render MarkdownContent component with headings given proper ids', async () => { await renderInTestApp( ', () => { it('renders without exploding', async () => { - jest.useFakeTimers(); - const { getByTestId, queryByTestId } = await renderInTestApp(); - expect(queryByTestId('progress')).not.toBeInTheDocument(); - act(() => { - jest.advanceTimersByTime(250); - }); - expect(getByTestId('progress')).toBeInTheDocument(); - jest.useRealTimers(); + const { queryByTestId } = await renderInTestApp(); + expect(queryByTestId('progress')).toBeInTheDocument(); }); }); diff --git a/packages/core-components/src/components/Progress/Progress.tsx b/packages/core-components/src/components/Progress/Progress.tsx index 6d1281edd5..865c4673b8 100644 --- a/packages/core-components/src/components/Progress/Progress.tsx +++ b/packages/core-components/src/components/Progress/Progress.tsx @@ -36,6 +36,6 @@ export function Progress(props: PropsWithChildren) { return isVisible ? ( ) : ( - + ); } diff --git a/packages/core-components/src/components/TrendLine/TrendLine.test.tsx b/packages/core-components/src/components/TrendLine/TrendLine.test.tsx index 0d98c2dfdc..3cb54875c5 100644 --- a/packages/core-components/src/components/TrendLine/TrendLine.test.tsx +++ b/packages/core-components/src/components/TrendLine/TrendLine.test.tsx @@ -43,14 +43,14 @@ describe('TrendLine', () => { }); }); - describe.skip('when the data finishes within the the warning threshold', () => { + describe.skip('when the data finishes within the warning threshold', () => { it('renders with the correct color', async () => { await renderInTestApp(); expect(screen.getByTitle('sparkline')).toBeInTheDocument(); }); }); - describe.skip('when the data finishes within the the error threshold', () => { + describe.skip('when the data finishes within the error threshold', () => { it('renders with the correct color', async () => { await renderInTestApp(); expect(screen.getByTitle('sparkline')).toBeInTheDocument(); diff --git a/packages/core-plugin-api/CHANGELOG.md b/packages/core-plugin-api/CHANGELOG.md index 0c5c3f0780..c74fe35878 100644 --- a/packages/core-plugin-api/CHANGELOG.md +++ b/packages/core-plugin-api/CHANGELOG.md @@ -1,5 +1,25 @@ # @backstage/core-plugin-api +## 1.10.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 1.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + - @backstage/version-bridge@1.0.10 + ## 1.10.0 ### Minor Changes diff --git a/packages/core-plugin-api/package.json b/packages/core-plugin-api/package.json index 0e54f32ff4..717b7d7150 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.0", + "version": "1.10.2-next.0", "description": "Core API used by Backstage plugins", "backstage": { "role": "web-library" diff --git a/packages/create-app/CHANGELOG.md b/packages/create-app/CHANGELOG.md index 25f308c1cd..6fc8da6e3e 100644 --- a/packages/create-app/CHANGELOG.md +++ b/packages/create-app/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/create-app +## 0.5.23-next.2 + +### Patch Changes + +- e913fdf: Add github backend module to create-app and improve error messages +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## 0.5.23-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## 0.5.23-next.0 + +### Patch Changes + +- 5819f8d: Updated Dockerfile to include `backstage.json` file +- 583f3d4: Updated the template to use `@backstage/cli/config/prettier` instead of `@spotify/prettier-config`. +- Updated dependencies + - @backstage/cli-common@0.1.15 + +## 0.5.22 + +### Patch Changes + +- 7907e3b: Bumped create-app version. +- 42386c2: Bumped create-app version. +- 702f41d: Updated engines to support Node 20 or 22 +- a917f86: This update adds the @backstage/repo-tools package to the versions.ts file, enabling proper version resolution for templates. The {{version '@backstage/repo-tools'}} placeholder now works as expected in the create-app process. +- 5872964: Use the main entrypoint for `create-app` installs +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/cli-common@0.1.15 + ## 0.5.22-next.3 ### Patch Changes diff --git a/packages/create-app/package.json b/packages/create-app/package.json index 2acc972a91..b3dbd768cc 100644 --- a/packages/create-app/package.json +++ b/packages/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/create-app", - "version": "0.5.22-next.3", + "version": "0.5.23-next.2", "description": "A CLI that helps you create your own Backstage app", "backstage": { "role": "cli" @@ -49,7 +49,6 @@ "fs-extra": "^11.2.0", "handlebars": "^4.7.3", "inquirer": "^8.2.0", - "node-fetch": "^2.7.0", "ora": "^5.3.0", "recursive-readdir": "^2.2.2" }, @@ -61,7 +60,7 @@ "@types/inquirer": "^8.1.3", "@types/node": "^20.16.0", "@types/recursive-readdir": "^2.2.0", - "msw": "^1.0.0", + "msw": "^2.0.0", "nodemon": "^3.0.1" } } diff --git a/packages/create-app/src/lib/tasks.test.ts b/packages/create-app/src/lib/tasks.test.ts index 41c20854be..3d5240977e 100644 --- a/packages/create-app/src/lib/tasks.test.ts +++ b/packages/create-app/src/lib/tasks.test.ts @@ -33,7 +33,7 @@ import { createMockDirectory, registerMswTestHooks, } from '@backstage/backend-test-utils'; -import { rest } from 'msw'; +import { http, HttpResponse, delay } from 'msw'; import { setupServer } from 'msw/node'; jest.spyOn(Task, 'log').mockReturnValue(undefined); @@ -91,6 +91,7 @@ jest.mock('./versions', () => ({ '@backstage/plugin-kubernetes-backend': '1.0.0', '@backstage/plugin-org': '1.0.0', '@backstage/plugin-scaffolder': '1.0.0', + '@backstage/plugin-scaffolder-backend-module-github': '1.0.0', '@backstage/plugin-permission-react': '1.0.0', '@backstage/plugin-search': '1.0.0', '@backstage/plugin-search-react': '1.0.0', @@ -402,12 +403,10 @@ describe('tasks', () => { it('should fetch the yarn.lock seed file', async () => { worker.use( - rest.get( + http.get( 'https://raw.githubusercontent.com/backstage/backstage/master/packages/create-app/seed-yarn.lock', - (_, res, ctx) => - res( - ctx.status(200), - ctx.text(`# the-lockfile-header + () => + HttpResponse.text(`# the-lockfile-header // some comments // in the file @@ -418,7 +417,6 @@ describe('tasks', () => { "@backstage/cli@1.0.0": some info `), - ), ), ); @@ -438,9 +436,9 @@ describe('tasks', () => { it('should fail gracefully', async () => { worker.use( - rest.get( + http.get( 'https://raw.githubusercontent.com/backstage/backstage/master/packages/create-app/seed-yarn.lock', - (_, res, ctx) => res(ctx.status(404)), + () => new HttpResponse(null, { status: 404 }), ), ); @@ -453,9 +451,9 @@ describe('tasks', () => { it('should time out if it takes too long to fetch', async () => { worker.use( - rest.get( + http.get( 'https://raw.githubusercontent.com/backstage/backstage/master/packages/create-app/seed-yarn.lock', - (_, res, ctx) => res(ctx.delay(5000)), + () => delay(5000), ), ); diff --git a/packages/create-app/src/lib/tasks.ts b/packages/create-app/src/lib/tasks.ts index a47f5f2cb9..51308275a6 100644 --- a/packages/create-app/src/lib/tasks.ts +++ b/packages/create-app/src/lib/tasks.ts @@ -25,7 +25,6 @@ import { resolve as resolvePath, relative as relativePath, } from 'path'; -import fetch from 'node-fetch'; import { exec as execCb } from 'child_process'; import { packageVersions } from './versions'; import { promisify } from 'util'; diff --git a/packages/create-app/src/lib/versions.ts b/packages/create-app/src/lib/versions.ts index 9a7158ea55..d06912cca3 100644 --- a/packages/create-app/src/lib/versions.ts +++ b/packages/create-app/src/lib/versions.ts @@ -72,6 +72,7 @@ import { version as pluginPermissionNode } from '../../../../plugins/permission- import { version as pluginProxyBackend } from '../../../../plugins/proxy-backend/package.json'; import { version as pluginScaffolder } from '../../../../plugins/scaffolder/package.json'; import { version as pluginScaffolderBackend } from '../../../../plugins/scaffolder-backend/package.json'; +import { version as pluginScaffolderBackendModuleGithub } from '../../../../plugins/scaffolder-backend-module-github/package.json'; import { version as pluginSearch } from '../../../../plugins/search/package.json'; import { version as pluginSearchReact } from '../../../../plugins/search-react/package.json'; import { version as pluginSearchBackend } from '../../../../plugins/search-backend/package.json'; @@ -130,6 +131,8 @@ export const packageVersions = { '@backstage/plugin-proxy-backend': pluginProxyBackend, '@backstage/plugin-scaffolder': pluginScaffolder, '@backstage/plugin-scaffolder-backend': pluginScaffolderBackend, + '@backstage/plugin-scaffolder-backend-module-github': + pluginScaffolderBackendModuleGithub, '@backstage/plugin-search': pluginSearch, '@backstage/plugin-search-react': pluginSearchReact, '@backstage/plugin-search-backend': pluginSearchBackend, diff --git a/packages/create-app/templates/default-app/package.json.hbs b/packages/create-app/templates/default-app/package.json.hbs index 73f97484f9..21bdd41bdf 100644 --- a/packages/create-app/templates/default-app/package.json.hbs +++ b/packages/create-app/templates/default-app/package.json.hbs @@ -34,7 +34,6 @@ "@backstage/cli": "^{{version '@backstage/cli'}}", "@backstage/e2e-test-utils": "^{{version '@backstage/e2e-test-utils'}}", "@playwright/test": "^1.32.3", - "@spotify/prettier-config": "^12.0.0", "node-gyp": "^10.0.0", "prettier": "^2.3.2", "typescript": "~5.4.0" @@ -43,7 +42,7 @@ "@types/react": "^18", "@types/react-dom": "^18" }, - "prettier": "@spotify/prettier-config", + "prettier": "@backstage/cli/config/prettier", "lint-staged": { "*.{js,jsx,ts,tsx,mjs,cjs}": [ "eslint --fix", diff --git a/packages/create-app/templates/default-app/packages/backend/Dockerfile b/packages/create-app/templates/default-app/packages/backend/Dockerfile index 6a4c257afb..13ff70d961 100644 --- a/packages/create-app/templates/default-app/packages/backend/Dockerfile +++ b/packages/create-app/templates/default-app/packages/backend/Dockerfile @@ -40,6 +40,7 @@ WORKDIR /app # Copy files needed by Yarn COPY --chown=node:node .yarn ./.yarn COPY --chown=node:node .yarnrc.yml ./ +COPY --chown=node:node backstage.json ./ # This switches many Node.js dependencies to production mode. ENV NODE_ENV=production diff --git a/packages/create-app/templates/default-app/packages/backend/package.json.hbs b/packages/create-app/templates/default-app/packages/backend/package.json.hbs index bb05beddaa..42afefd3b8 100644 --- a/packages/create-app/templates/default-app/packages/backend/package.json.hbs +++ b/packages/create-app/templates/default-app/packages/backend/package.json.hbs @@ -33,6 +33,7 @@ "@backstage/plugin-permission-node": "^{{version '@backstage/plugin-permission-node'}}", "@backstage/plugin-proxy-backend": "^{{version '@backstage/plugin-proxy-backend'}}", "@backstage/plugin-scaffolder-backend": "^{{version '@backstage/plugin-scaffolder-backend'}}", + "@backstage/plugin-scaffolder-backend-module-github": "^{{version '@backstage/plugin-scaffolder-backend-module-github'}}", "@backstage/plugin-search-backend": "^{{version '@backstage/plugin-search-backend'}}", "@backstage/plugin-search-backend-module-catalog": "^{{version '@backstage/plugin-search-backend-module-catalog'}}", "@backstage/plugin-search-backend-module-pg": "^{{version '@backstage/plugin-search-backend-module-pg'}}", diff --git a/packages/create-app/templates/default-app/packages/backend/src/index.ts b/packages/create-app/templates/default-app/packages/backend/src/index.ts index 69a73511c6..6d0a6f4ca5 100644 --- a/packages/create-app/templates/default-app/packages/backend/src/index.ts +++ b/packages/create-app/templates/default-app/packages/backend/src/index.ts @@ -13,6 +13,7 @@ const backend = createBackend(); backend.add(import('@backstage/plugin-app-backend')); backend.add(import('@backstage/plugin-proxy-backend')); backend.add(import('@backstage/plugin-scaffolder-backend')); +backend.add(import('@backstage/plugin-scaffolder-backend-module-github')); backend.add(import('@backstage/plugin-techdocs-backend')); // auth plugin diff --git a/packages/dev-utils/CHANGELOG.md b/packages/dev-utils/CHANGELOG.md index b28f82806d..e6cd7eeb73 100644 --- a/packages/dev-utils/CHANGELOG.md +++ b/packages/dev-utils/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/dev-utils +## 1.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + +## 1.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + +## 1.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + +## 1.1.3 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.1 + ## 1.1.3-next.3 ### Patch Changes diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index dd7c88f57e..c4aef9fd83 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/dev-utils", - "version": "1.1.3-next.3", + "version": "1.1.5-next.2", "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 96fe6c9d82..4feec740ca 100644 --- a/packages/e2e-test/CHANGELOG.md +++ b/packages/e2e-test/CHANGELOG.md @@ -1,5 +1,41 @@ # e2e-test +## 0.2.23-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-common@0.1.15 + +## 0.2.23-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## 0.2.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.23-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + +## 0.2.22 + +### Patch Changes + +- Updated dependencies + - @backstage/create-app@0.5.22 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + ## 0.2.22-next.3 ### Patch Changes diff --git a/packages/e2e-test/package.json b/packages/e2e-test/package.json index 0d6b782f07..ca2f005a31 100644 --- a/packages/e2e-test/package.json +++ b/packages/e2e-test/package.json @@ -1,6 +1,6 @@ { "name": "e2e-test", - "version": "0.2.22-next.3", + "version": "0.2.23-next.2", "description": "E2E test for verifying Backstage packages", "backstage": { "role": "cli" diff --git a/packages/errors/CHANGELOG.md b/packages/errors/CHANGELOG.md index 5cdaa834fd..33204aae4c 100644 --- a/packages/errors/CHANGELOG.md +++ b/packages/errors/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/errors +## 1.2.6-next.0 + +### Patch Changes + +- 1d4b5b9: Trim `error.cause.stack` in addition to `error.stack` when trimming stack traces from serialized errors. +- Updated dependencies + - @backstage/types@1.2.0 + +## 1.2.5 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + ## 1.2.4 ### Patch Changes diff --git a/packages/errors/package.json b/packages/errors/package.json index dcc46ac51e..fa2a600085 100644 --- a/packages/errors/package.json +++ b/packages/errors/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/errors", - "version": "1.2.4", + "version": "1.2.6-next.0", "description": "Common utilities for error handling within Backstage", "backstage": { "role": "common-library" diff --git a/packages/errors/src/serialization/error.test.ts b/packages/errors/src/serialization/error.test.ts index a07d11749a..6418170f98 100644 --- a/packages/errors/src/serialization/error.test.ts +++ b/packages/errors/src/serialization/error.test.ts @@ -63,6 +63,20 @@ describe('serialization', () => { expect(withoutStack2.stack).not.toBeDefined(); }); + it('serializes stack traces only when allowed with error cause', () => { + const before = new CustomError('m'); + before.cause = new Error('cause'); + const withStack: any = serializeError(before, { includeStack: true }); + const withoutStack1: any = serializeError(before, { includeStack: false }); + const withoutStack2: any = serializeError(before); + expect(withStack.stack).toEqual(before.stack); + expect(withStack.cause.stack).toEqual(withStack.cause.stack); + expect(withoutStack1.stack).not.toBeDefined(); + expect(withoutStack2.stack).not.toBeDefined(); + expect(withoutStack1.cause.stack).not.toBeDefined(); + expect(withoutStack2.cause.stack).not.toBeDefined(); + }); + it('stringifies all supported forms', () => { expect(stringifyError({})).toEqual("unknown error '[object Object]'"); expect( diff --git a/packages/errors/src/serialization/error.ts b/packages/errors/src/serialization/error.ts index e48309f1e7..abdd7bf3d4 100644 --- a/packages/errors/src/serialization/error.ts +++ b/packages/errors/src/serialization/error.ts @@ -60,6 +60,14 @@ export function serializeError( if (!options?.includeStack) { delete result.stack; + + if ( + result.cause && + typeof result.cause === 'object' && + 'stack' in result.cause + ) { + delete result.cause.stack; + } } return result; diff --git a/packages/frontend-app-api/CHANGELOG.md b/packages/frontend-app-api/CHANGELOG.md index 4f23c09ec3..9751a9845c 100644 --- a/packages/frontend-app-api/CHANGELOG.md +++ b/packages/frontend-app-api/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/frontend-app-api +## 0.10.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-defaults@0.1.4-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.10.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-defaults@0.1.4-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.10.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-defaults@0.1.4-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.10.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/core-app-api@1.15.2 + - @backstage/frontend-defaults@0.1.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + ## 0.10.1-next.2 ### Patch Changes diff --git a/packages/frontend-app-api/package.json b/packages/frontend-app-api/package.json index 6ee3857320..8f2215962c 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.10.1-next.2", + "version": "0.10.3-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-defaults/CHANGELOG.md b/packages/frontend-defaults/CHANGELOG.md index ca769208b6..7bc7e229ec 100644 --- a/packages/frontend-defaults/CHANGELOG.md +++ b/packages/frontend-defaults/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/frontend-defaults +## 0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-app@0.1.4-next.2 + +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-app@0.1.4-next.1 + +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.3-next.0 + +## 0.1.2 + +### Patch Changes + +- 44b82da: The default config loader no longer requires `process.env.APP_CONFIG` to be set, allowing config to be read from other sources instead. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-app@0.1.2 + ## 0.1.2-next.2 ### Patch Changes diff --git a/packages/frontend-defaults/package.json b/packages/frontend-defaults/package.json index 61603140bf..2d6c1a7a86 100644 --- a/packages/frontend-defaults/package.json +++ b/packages/frontend-defaults/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/frontend-defaults", - "version": "0.1.2-next.2", + "version": "0.1.4-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-internal/CHANGELOG.md b/packages/frontend-internal/CHANGELOG.md index 4ad77bcb30..0ac6c8558e 100644 --- a/packages/frontend-internal/CHANGELOG.md +++ b/packages/frontend-internal/CHANGELOG.md @@ -1,5 +1,41 @@ # @internal/frontend +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + ## 0.0.3-next.2 ### Patch Changes diff --git a/packages/frontend-internal/package.json b/packages/frontend-internal/package.json index f80bc9a9f0..bbe8e3df17 100644 --- a/packages/frontend-internal/package.json +++ b/packages/frontend-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/frontend", - "version": "0.0.3-next.2", + "version": "0.0.4-next.2", "backstage": { "role": "web-library", "inline": true diff --git a/packages/frontend-plugin-api/CHANGELOG.md b/packages/frontend-plugin-api/CHANGELOG.md index b058260ec0..9aacfe0485 100644 --- a/packages/frontend-plugin-api/CHANGELOG.md +++ b/packages/frontend-plugin-api/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/frontend-plugin-api +## 0.9.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.9.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.9.3-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.9.1 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + ## 0.9.1-next.2 ### Patch Changes diff --git a/packages/frontend-plugin-api/package.json b/packages/frontend-plugin-api/package.json index 7818d8210c..c2a9fd8d8b 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.9.1-next.2", + "version": "0.9.3-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx index de1cbe211e..4d0b4f37a7 100644 --- a/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx +++ b/packages/frontend-plugin-api/src/blueprints/PageBlueprint.test.tsx @@ -98,7 +98,7 @@ describe('PageBlueprint', () => { const tester = createExtensionTester(myPage); - // TODO(blam): test for the routePath output doesn't work, due to the the way the test harness works + // TODO(blam): test for the routePath output doesn't work, due to the way the test harness works // expect(tester.data(coreExtensionData.routePath)).toBe('/test'); expect(tester.get(coreExtensionData.routeRef)).toBe(mockRouteRef); diff --git a/packages/frontend-test-utils/CHANGELOG.md b/packages/frontend-test-utils/CHANGELOG.md index bc74f59702..40d8e62884 100644 --- a/packages/frontend-test-utils/CHANGELOG.md +++ b/packages/frontend-test-utils/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/frontend-test-utils +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/frontend-app-api@0.10.3-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/test-utils@1.7.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.4-next.2 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/frontend-app-api@0.10.3-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.4-next.1 + +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-app@0.1.4-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/config@1.3.0 + - @backstage/frontend-app-api@0.10.3-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/frontend-app-api@0.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/test-utils@1.7.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-app@0.1.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/packages/frontend-test-utils/package.json b/packages/frontend-test-utils/package.json index f8e285b625..8a13dda074 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.2.2-next.2", + "version": "0.2.4-next.2", "backstage": { "role": "web-library" }, diff --git a/packages/integration-aws-node/CHANGELOG.md b/packages/integration-aws-node/CHANGELOG.md index 01357679be..66d93b93c1 100644 --- a/packages/integration-aws-node/CHANGELOG.md +++ b/packages/integration-aws-node/CHANGELOG.md @@ -1,5 +1,22 @@ # @backstage/integration-aws-node +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + +## 0.1.13 + +### Patch Changes + +- 52ae92d: The `getDefaultCredentialsChain` function now accepts and applies a `region` parameter, preventing it from defaulting to `us-east-1` when no region is specified. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + ## 0.1.13-next.0 ### Patch Changes diff --git a/packages/integration-aws-node/package.json b/packages/integration-aws-node/package.json index 107b99f9bb..e1fbcf6fac 100644 --- a/packages/integration-aws-node/package.json +++ b/packages/integration-aws-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-aws-node", - "version": "0.1.13-next.0", + "version": "0.1.14-next.0", "description": "Helpers for fetching AWS account credentials", "backstage": { "role": "node-library" diff --git a/packages/integration-react/CHANGELOG.md b/packages/integration-react/CHANGELOG.md index 2b686905ab..57698d9a0f 100644 --- a/packages/integration-react/CHANGELOG.md +++ b/packages/integration-react/CHANGELOG.md @@ -1,5 +1,32 @@ # @backstage/integration-react +## 1.2.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration@1.16.0-next.1 + +## 1.2.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + +## 1.2.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.15.2 + ## 1.2.0 ### Minor Changes diff --git a/packages/integration-react/package.json b/packages/integration-react/package.json index c524d82d31..b1c8ff60f9 100644 --- a/packages/integration-react/package.json +++ b/packages/integration-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration-react", - "version": "1.2.0", + "version": "1.2.2-next.1", "description": "Frontend package for managing integrations towards external systems", "backstage": { "role": "web-library" diff --git a/packages/integration-react/src/api/ScmIntegrationsApi.test.ts b/packages/integration-react/src/api/ScmIntegrationsApi.test.ts index fb53bbdb12..0a1f1b1b8f 100644 --- a/packages/integration-react/src/api/ScmIntegrationsApi.test.ts +++ b/packages/integration-react/src/api/ScmIntegrationsApi.test.ts @@ -26,6 +26,6 @@ describe('scmIntegrationsApiRef', () => { it('should be instantiated', () => { const i = ScmIntegrationsApi.fromConfig(new ConfigReader({})); - expect(i.list().length).toBe(6); // The default ones + expect(i.list().length).toBe(7); // The default ones }); }); diff --git a/packages/integration/CHANGELOG.md b/packages/integration/CHANGELOG.md index 5b5165bd53..8af904036e 100644 --- a/packages/integration/CHANGELOG.md +++ b/packages/integration/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/integration +## 1.16.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + +## 1.16.0-next.0 + +### Minor Changes + +- 277092a: Add the integration for Azure blob storage to read the credentials to access the storage account and provide the default credential provider. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 1.15.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + ## 1.15.1 ### Patch Changes diff --git a/packages/integration/package.json b/packages/integration/package.json index d41ffa501d..9b09adaf1b 100644 --- a/packages/integration/package.json +++ b/packages/integration/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/integration", - "version": "1.15.1", + "version": "1.16.0-next.1", "description": "Helpers for managing integrations towards external systems", "backstage": { "role": "common-library" @@ -38,6 +38,7 @@ }, "dependencies": { "@azure/identity": "^4.0.0", + "@azure/storage-blob": "^12.5.0", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@octokit/auth-app": "^4.0.0", diff --git a/packages/integration/report.api.md b/packages/integration/report.api.md index e9b67bb6c1..5129dbb7c2 100644 --- a/packages/integration/report.api.md +++ b/packages/integration/report.api.md @@ -3,9 +3,12 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnonymousCredential } from '@azure/storage-blob'; import { Config } from '@backstage/config'; import { ConsumedResponse } from '@backstage/errors'; import { RestEndpointMethodTypes } from '@octokit/rest'; +import { StorageSharedKeyCredential } from '@azure/storage-blob'; +import { TokenCredential } from '@azure/identity'; // @public export class AwsCodeCommitIntegration implements ScmIntegration { @@ -70,6 +73,43 @@ export type AwsS3IntegrationConfig = { externalId?: string; }; +// @public +export type AzureBlobStorageIntegrationConfig = { + accountName?: string; + accountKey?: string; + sasToken?: string; + connectionString?: string; + endpointSuffix?: string; + host: string; + endpoint?: string; + aadCredential?: { + clientId: string; + tenantId: string; + clientSecret: string; + }; +}; + +// @public +export class AzureBlobStorageIntergation implements ScmIntegration { + constructor(integrationConfig: AzureBlobStorageIntegrationConfig); + // (undocumented) + get config(): AzureBlobStorageIntegrationConfig; + // (undocumented) + static factory: ScmIntegrationsFactory; + // (undocumented) + resolveEditUrl(url: string): string; + // (undocumented) + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string; + // (undocumented) + get title(): string; + // (undocumented) + get type(): string; +} + // @public export type AzureClientSecretCredential = AzureCredentialBase & { kind: 'ClientSecret'; @@ -84,6 +124,16 @@ export type AzureCredentialBase = { organizations?: string[]; }; +// @public +export interface AzureCredentialsManager { + // (undocumented) + getCredentials( + accountName: string, + ): Promise< + TokenCredential | StorageSharedKeyCredential | AnonymousCredential + >; +} + // @public export type AzureDevOpsCredential = | AzureClientSecretCredential @@ -257,6 +307,15 @@ export function buildGerritGitilesArchiveUrl( filePath: string, ): string; +// @public +export class DefaultAzureCredentialsManager implements AzureCredentialsManager { + static fromIntegrations( + integrations: ScmIntegrationRegistry, + ): DefaultAzureCredentialsManager; + // (undocumented) + getCredentials(accountName: string): Promise; +} + // @public export class DefaultAzureDevOpsCredentialsProvider implements AzureDevOpsCredentialsProvider @@ -723,6 +782,8 @@ export interface IntegrationsByType { awsS3: ScmIntegrationsGroup; // (undocumented) azure: ScmIntegrationsGroup; + // (undocumented) + azureBlobStorage: ScmIntegrationsGroup; // @deprecated (undocumented) bitbucket: ScmIntegrationsGroup; // (undocumented) @@ -826,6 +887,16 @@ export function readAwsS3IntegrationConfigs( configs: Config[], ): AwsS3IntegrationConfig[]; +// @public +export function readAzureBlobStorageIntegrationConfig( + config: Config, +): AzureBlobStorageIntegrationConfig; + +// @public +export function readAzureBlobStorageIntegrationConfigs( + configs: Config[], +): AzureBlobStorageIntegrationConfig[]; + // @public export function readAzureIntegrationConfig( config: Config, @@ -940,6 +1011,8 @@ export interface ScmIntegrationRegistry awsS3: ScmIntegrationsGroup; // (undocumented) azure: ScmIntegrationsGroup; + // (undocumented) + azureBlobStorage: ScmIntegrationsGroup; // @deprecated (undocumented) bitbucket: ScmIntegrationsGroup; // (undocumented) @@ -973,6 +1046,8 @@ export class ScmIntegrations implements ScmIntegrationRegistry { get awsS3(): ScmIntegrationsGroup; // (undocumented) get azure(): ScmIntegrationsGroup; + // (undocumented) + get azureBlobStorage(): ScmIntegrationsGroup; // @deprecated (undocumented) get bitbucket(): ScmIntegrationsGroup; // (undocumented) diff --git a/packages/integration/src/ScmIntegrations.test.ts b/packages/integration/src/ScmIntegrations.test.ts index c758816c03..0e0c181861 100644 --- a/packages/integration/src/ScmIntegrations.test.ts +++ b/packages/integration/src/ScmIntegrations.test.ts @@ -39,6 +39,10 @@ import { GiteaIntegration, GiteaIntegrationConfig } from './gitea'; import { AwsCodeCommitIntegration } from './awsCodeCommit/AwsCodeCommitIntegration'; import { AwsCodeCommitIntegrationConfig } from './awsCodeCommit'; import { HarnessIntegration, HarnessIntegrationConfig } from './harness'; +import { + AzureBlobStorageIntegrationConfig, + AzureBlobStorageIntergation, +} from './azureBlobStorage'; describe('ScmIntegrations', () => { const awsS3 = new AwsS3Integration({ @@ -53,6 +57,10 @@ describe('ScmIntegrations', () => { host: 'azure.local', } as AzureIntegrationConfig); + const azureBlob = new AzureBlobStorageIntergation({ + host: 'azureblobstorage.local', + } as AzureBlobStorageIntegrationConfig); + const bitbucket = new BitbucketIntegration({ host: 'bitbucket.local', } as BitbucketIntegrationConfig); @@ -89,6 +97,7 @@ describe('ScmIntegrations', () => { awsS3: basicIntegrations([awsS3], item => item.config.host), awsCodeCommit: basicIntegrations([awsCodeCommit], item => item.config.host), azure: basicIntegrations([azure], item => item.config.host), + azureBlobStorage: basicIntegrations([azureBlob], item => item.config.host), bitbucket: basicIntegrations([bitbucket], item => item.config.host), bitbucketCloud: basicIntegrations([bitbucketCloud], item => item.title), bitbucketServer: basicIntegrations( @@ -108,6 +117,9 @@ describe('ScmIntegrations', () => { awsCodeCommit, ); expect(i.azure.byUrl('https://azure.local')).toBe(azure); + expect(i.azureBlobStorage.byUrl('https://azureblobstorage.local')).toBe( + azureBlob, + ); expect(i.bitbucket.byUrl('https://bitbucket.local')).toBe(bitbucket); expect(i.bitbucketCloud.byUrl('https://bitbucket.org')).toBe( bitbucketCloud, @@ -128,6 +140,7 @@ describe('ScmIntegrations', () => { awsS3, awsCodeCommit, azure, + azureBlob, bitbucket, bitbucketCloud, bitbucketServer, @@ -144,6 +157,9 @@ describe('ScmIntegrations', () => { expect(i.byUrl('https://awss3.local')).toBe(awsS3); expect(i.byUrl('https://awscodecommit.local')).toBe(awsCodeCommit); expect(i.byUrl('https://azure.local')).toBe(azure); + expect(i.azureBlobStorage.byUrl('https://azureblobstorage.local')).toBe( + azureBlob, + ); expect(i.byUrl('https://bitbucket.local')).toBe(bitbucket); expect(i.byUrl('https://bitbucket.org')).toBe(bitbucketCloud); expect(i.byUrl('https://bitbucket-server.local')).toBe(bitbucketServer); @@ -156,6 +172,7 @@ describe('ScmIntegrations', () => { expect(i.byHost('awss3.local')).toBe(awsS3); expect(i.byHost('awscodecommit.local')).toBe(awsCodeCommit); expect(i.byHost('azure.local')).toBe(azure); + expect(i.byHost('azureblobstorage.local')).toBe(azureBlob); expect(i.byHost('bitbucket.local')).toBe(bitbucket); expect(i.byHost('bitbucket.org')).toBe(bitbucketCloud); expect(i.byHost('bitbucket-server.local')).toBe(bitbucketServer); diff --git a/packages/integration/src/ScmIntegrations.ts b/packages/integration/src/ScmIntegrations.ts index e0d430d834..f11cb3c17e 100644 --- a/packages/integration/src/ScmIntegrations.ts +++ b/packages/integration/src/ScmIntegrations.ts @@ -29,6 +29,7 @@ import { ScmIntegration, ScmIntegrationsGroup } from './types'; import { ScmIntegrationRegistry } from './registry'; import { GiteaIntegration } from './gitea'; import { HarnessIntegration } from './harness/HarnessIntegration'; +import { AzureBlobStorageIntergation } from './azureBlobStorage'; /** * The set of supported integrations. @@ -38,6 +39,7 @@ import { HarnessIntegration } from './harness/HarnessIntegration'; export interface IntegrationsByType { awsS3: ScmIntegrationsGroup; awsCodeCommit: ScmIntegrationsGroup; + azureBlobStorage: ScmIntegrationsGroup; azure: ScmIntegrationsGroup; /** * @deprecated in favor of `bitbucketCloud` and `bitbucketServer` @@ -64,6 +66,7 @@ export class ScmIntegrations implements ScmIntegrationRegistry { return new ScmIntegrations({ awsS3: AwsS3Integration.factory({ config }), awsCodeCommit: AwsCodeCommitIntegration.factory({ config }), + azureBlobStorage: AzureBlobStorageIntergation.factory({ config }), azure: AzureIntegration.factory({ config }), bitbucket: BitbucketIntegration.factory({ config }), bitbucketCloud: BitbucketCloudIntegration.factory({ config }), @@ -88,6 +91,10 @@ export class ScmIntegrations implements ScmIntegrationRegistry { return this.byType.awsCodeCommit; } + get azureBlobStorage(): ScmIntegrationsGroup { + return this.byType.azureBlobStorage; + } + get azure(): ScmIntegrationsGroup { return this.byType.azure; } diff --git a/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.test.ts b/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.test.ts new file mode 100644 index 0000000000..e7f7703be9 --- /dev/null +++ b/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.test.ts @@ -0,0 +1,78 @@ +/* + * 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 { ConfigReader } from '@backstage/config'; +import { AzureBlobStorageIntergation } from './AzureBlobStorageIntegration'; + +describe('AzureBlobStorageIntegration', () => { + it('has a working factory', () => { + const integrations = AzureBlobStorageIntergation.factory({ + config: new ConfigReader({ + integrations: { + azureBlobStorage: [ + { + endpoint: 'https://myaccount.blob.core.windows.net', + accountName: 'myaccount', + accountKey: 'someAccountKey', + }, + ], + }, + }), + }); + expect(integrations.list().length).toBe(2); // including default + expect(integrations.list()[0].config.host).toBe( + 'myaccount.blob.core.windows.net', + ); + expect(integrations.list()[1].config.host).toBe('blob.core.windows.net'); // default integration + }); + + it('returns the basics', () => { + const integration = new AzureBlobStorageIntergation({ + host: 'myaccount.blob.core.windows.net', + } as any); + expect(integration.type).toBe('azureBlobStorage'); + expect(integration.title).toBe('myaccount.blob.core.windows.net'); + }); + + describe('resolveUrl', () => { + it('works for valid URLs', () => { + const integration = new AzureBlobStorageIntergation({ + host: 'blob.core.windows.net', + } as any); + + expect( + integration.resolveUrl({ + url: 'https://myaccount.blob.core.windows.net/container/file.yaml', + base: 'https://myaccount.blob.core.windows.net/container/file.yaml', + }), + ).toBe('https://myaccount.blob.core.windows.net/container/file.yaml'); + }); + }); + + it('resolve edit URL', () => { + const integration = new AzureBlobStorageIntergation({ + host: 'myaccount.blob.core.windows.net', + } as any); + + // TODO: The Azure Blob Storage integration doesn't support resolving an edit URL, + // instead we keep the input URL. + expect( + integration.resolveEditUrl( + 'https://myaccount.blob.core.windows.net/container/file.yaml', + ), + ).toBe('https://myaccount.blob.core.windows.net/container/file.yaml'); + }); +}); diff --git a/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.ts b/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.ts new file mode 100644 index 0000000000..27061f7d9d --- /dev/null +++ b/packages/integration/src/azureBlobStorage/AzureBlobStorageIntegration.ts @@ -0,0 +1,71 @@ +/* + * 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 { basicIntegrations, defaultScmResolveUrl } from '../helpers'; +import { ScmIntegration, ScmIntegrationsFactory } from '../types'; +import { + AzureBlobStorageIntegrationConfig, + readAzureBlobStorageIntegrationConfigs, +} from './config'; + +/** + * Microsoft Azure Blob storage based integration. + * + * @public + */ +export class AzureBlobStorageIntergation implements ScmIntegration { + static factory: ScmIntegrationsFactory = ({ + config, + }) => { + const configs = readAzureBlobStorageIntegrationConfigs( + config.getOptionalConfigArray('integrations.azureBlobStorage') ?? [], + ); + return basicIntegrations( + configs.map(c => new AzureBlobStorageIntergation(c)), + i => i.config.host, + ); + }; + + get type(): string { + return 'azureBlobStorage'; + } + + get title(): string { + return this.integrationConfig.host; + } + + get config(): AzureBlobStorageIntegrationConfig { + return this.integrationConfig; + } + + constructor( + private readonly integrationConfig: AzureBlobStorageIntegrationConfig, + ) {} + + resolveUrl(options: { + url: string; + base: string; + lineNumber?: number | undefined; + }): string { + const resolved = defaultScmResolveUrl(options); + return resolved; + } + + resolveEditUrl(url: string): string { + // TODO: Implement edit URL for azureBlobStorage + return url; + } +} diff --git a/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsManager.test.ts b/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsManager.test.ts new file mode 100644 index 0000000000..d8e8be2919 --- /dev/null +++ b/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsManager.test.ts @@ -0,0 +1,149 @@ +/* + * 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 { + AccessToken, + ClientSecretCredential, + DefaultAzureCredential, +} from '@azure/identity'; +import { ScmIntegrationRegistry } from '../registry'; +import { ConfigReader } from '@backstage/config'; +import { DefaultAzureCredentialsManager } from './DefaultAzureCredentialsProvider'; +import { ScmIntegrations } from '../ScmIntegrations'; +import { DateTime } from 'luxon'; + +const MockedClientSecretCredential = ClientSecretCredential as jest.MockedClass< + typeof ClientSecretCredential +>; + +jest.mock('@azure/identity'); + +describe('DefaultAzureCredentialsManager', () => { + let mockIntegration: ScmIntegrationRegistry; + + const buildProvider = (azureIntegrations: any[]) => + DefaultAzureCredentialsManager.fromIntegrations( + ScmIntegrations.fromConfig( + new ConfigReader({ + integrations: { + azureBlobStorage: azureIntegrations, + }, + }), + ), + ); + + beforeEach(() => { + mockIntegration = { + azureBlobStorage: { + list: jest.fn().mockReturnValue([ + { + config: { + accountName: 'testaccount', + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }, + }, + ]), + }, + } as unknown as ScmIntegrationRegistry; + + MockedClientSecretCredential.prototype.getToken.mockImplementation(() => + Promise.resolve({ + expiresOnTimestamp: DateTime.local().plus({ days: 1 }).toSeconds(), + token: 'fake-client-secret-token', + } as AccessToken), + ); + }); + + it('should create an instance from ScmIntegrationRegistry', () => { + const manager = + DefaultAzureCredentialsManager.fromIntegrations(mockIntegration); + expect(manager).toBeInstanceOf(DefaultAzureCredentialsManager); + }); + + it('should return cached credentials if available', async () => { + const manager = buildProvider([ + { + accountName: 'testaccount', + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }, + ]); + + const mockCredential = new MockedClientSecretCredential( + 'someTenantId', + 'someClientId', + 'someClientSecret', + ); + + const credential = await manager.getCredentials('testaccount'); + + const scopes = ['https://storage.azure.com/.default']; + + const expectedToken = await mockCredential.getToken(scopes); + const receivedToken = await credential.getToken(scopes); + + expect(receivedToken?.token).toEqual(expectedToken.token); + }); + + it('should use Azure AD credentials if aadCredential is provided', async () => { + const manager = buildProvider([ + { + accountName: 'testaccount', + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }, + ]); + + const credential = await manager.getCredentials('testaccount'); + + expect(credential).toBeInstanceOf(ClientSecretCredential); + }); + + it('should use DefaultAzureCredential if no aadCredential is provided', async () => { + const manager = buildProvider([ + { + accountName: 'testaccount', + }, + ]); + + const credential = await manager.getCredentials('testaccount'); + + expect(credential).toBeInstanceOf(DefaultAzureCredential); + }); + + it('should cache credentials after first retrieval', async () => { + const manager = buildProvider([ + { + accountName: 'testaccount', + }, + ]); + + const credential = await manager.getCredentials('testaccount'); + + const cachedCredential = await manager.getCredentials('testaccount'); + expect(cachedCredential).toBe(credential); + }); +}); diff --git a/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsProvider.ts b/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsProvider.ts new file mode 100644 index 0000000000..3861329300 --- /dev/null +++ b/packages/integration/src/azureBlobStorage/DefaultAzureCredentialsProvider.ts @@ -0,0 +1,97 @@ +/* + * 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 { + DefaultAzureCredential, + ClientSecretCredential, + TokenCredential, +} from '@azure/identity'; +import { AzureBlobStorageIntegrationConfig } from './config'; +import { AzureCredentialsManager } from './types'; +import { ScmIntegrationRegistry } from '../registry'; + +/** + * Default implementation of AzureCredentialsManager that supports multiple Azure Blob Storage integrations. + * @public + */ +export class DefaultAzureCredentialsManager implements AzureCredentialsManager { + private cachedCredentials: Map; + + private constructor( + private readonly configProviders: Map< + string, + AzureBlobStorageIntegrationConfig + >, + ) { + this.cachedCredentials = new Map(); + } + + /** + * Creates an instance of DefaultAzureCredentialsManager from a Backstage integration registry. + */ + static fromIntegrations( + integrations: ScmIntegrationRegistry, + ): DefaultAzureCredentialsManager { + const configProviders = integrations.azureBlobStorage + .list() + .reduce((acc, integration) => { + acc.set( + integration.config.accountName || 'default', + integration.config, + ); + return acc; + }, new Map()); + + return new DefaultAzureCredentialsManager(configProviders); + } + + private createCredential( + config: AzureBlobStorageIntegrationConfig, + ): TokenCredential { + if ( + config.aadCredential && + config.aadCredential.clientId && + config.aadCredential.clientSecret && + config.aadCredential.tenantId + ) { + return new ClientSecretCredential( + config.aadCredential.tenantId, + config.aadCredential.clientId, + config.aadCredential.clientSecret, + ); + } + + return new DefaultAzureCredential(); + } + + async getCredentials(accountName: string): Promise { + if (this.cachedCredentials.has(accountName)) { + return this.cachedCredentials.get(accountName)!; + } + + const config = this.configProviders.get(accountName); + if (!config) { + throw new Error(`No configuration found for account: ${accountName}`); + } + + const credential = this.createCredential(config); + + // Cache the credentials for future use + this.cachedCredentials.set(accountName, credential); + + return credential; + } +} diff --git a/packages/integration/src/azureBlobStorage/config.test.ts b/packages/integration/src/azureBlobStorage/config.test.ts new file mode 100644 index 0000000000..f17bdf3efb --- /dev/null +++ b/packages/integration/src/azureBlobStorage/config.test.ts @@ -0,0 +1,264 @@ +/* + * 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, ConfigReader } from '@backstage/config'; +import { + AzureBlobStorageIntegrationConfig, + readAzureBlobStorageIntegrationConfig, + readAzureBlobStorageIntegrationConfigs, +} from './config'; + +describe('readAzureBlobStorageIntegrationConfig', () => { + function buildConfig( + data: Partial, + ): Config { + return new ConfigReader(data); + } + + it('reads valid configuration with accountKey', () => { + const output = readAzureBlobStorageIntegrationConfig( + buildConfig({ + accountName: 'mystorageaccount', + accountKey: 'someAccountKey', + }), + ); + expect(output).toEqual({ + host: 'blob.core.windows.net', + endpoint: undefined, + accountName: 'mystorageaccount', + accountKey: 'someAccountKey', + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }); + }); + + it('reads valid configuration with sasToken', () => { + const output = readAzureBlobStorageIntegrationConfig( + buildConfig({ + endpoint: 'https://blob.core.windows.net', + accountName: 'mystorageaccount', + sasToken: 'someSASToken', + }), + ); + expect(output).toEqual({ + host: 'blob.core.windows.net', + endpoint: 'https://blob.core.windows.net', + accountName: 'mystorageaccount', + accountKey: undefined, + sasToken: 'someSASToken', + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }); + }); + + it('reads valid configuration with Azure AD credentials', () => { + const output = readAzureBlobStorageIntegrationConfig( + buildConfig({ + accountName: 'mystorageaccount', + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }), + ); + expect(output).toEqual({ + host: 'blob.core.windows.net', + endpoint: undefined, + accountName: 'mystorageaccount', + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }); + }); + + it('reads valid configuration with a custom endpoint', () => { + const output = readAzureBlobStorageIntegrationConfig( + buildConfig({ + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'customaccount', + }), + ); + expect(output).toEqual({ + host: 'custom.blob.core.windows.net', + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'customaccount', + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }); + }); + + it('throws error for invalid endpoint URL', () => { + const config = buildConfig({ + endpoint: 'invalid-url', + accountName: 'invalidaccount', + }); + + expect(() => readAzureBlobStorageIntegrationConfig(config)).toThrow( + `invalid azureBlobStorage integration config, endpoint 'invalid-url' is not a valid URL`, + ); + }); + + it('throws error if endpoint has a path', () => { + const config = buildConfig({ + endpoint: 'https://blob.core.windows.net/path', + accountName: 'accountwithpath', + }); + + expect(() => readAzureBlobStorageIntegrationConfig(config)).toThrow( + `invalid azureBlobStorage integration config, endpoints cannot contain path, got 'https://blob.core.windows.net/path'`, + ); + }); + + it('throws error if both accountKey and sasToken are provided', () => { + const config = buildConfig({ + accountName: 'mystorageaccount', + accountKey: 'someAccountKey', + sasToken: 'someSASToken', + }); + + expect(() => readAzureBlobStorageIntegrationConfig(config)).toThrow( + `Invalid Azure Blob Storage config for mystorageaccount: Both account key and SAS token cannot be used simultaneously.`, + ); + }); + + it('throws error if both aadCredential and accountKey/sasToken are provided', () => { + const config = buildConfig({ + accountName: 'mystorageaccount', + accountKey: 'someAccountKey', + aadCredential: { + clientId: 'someClientId', + tenantId: 'someTenantId', + clientSecret: 'someClientSecret', + }, + }); + + expect(() => readAzureBlobStorageIntegrationConfig(config)).toThrow( + `Invalid Azure Blob Storage config for mystorageaccount: Cannot use both Azure AD credentials and account keys/SAS tokens for the same account.`, + ); + }); +}); + +describe('readAzureBlobStorageIntegrationConfigs', () => { + function buildConfigs( + data: Partial[], + ): Config[] { + return data.map(item => new ConfigReader(item)); + } + + it('reads all provided configurations', () => { + const output = readAzureBlobStorageIntegrationConfigs( + buildConfigs([ + { + host: 'blob.core.windows.net', + accountName: 'account1', + accountKey: 'someAccountKey', + }, + { + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'account2', + }, + ]), + ); + expect(output).toEqual([ + { + host: 'blob.core.windows.net', + endpoint: undefined, + accountName: 'account1', + accountKey: 'someAccountKey', + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }, + { + host: 'custom.blob.core.windows.net', + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'account2', + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }, + ]); + }); + + it('adds default integration for blob.core.windows.net when missing', () => { + const output = readAzureBlobStorageIntegrationConfigs( + buildConfigs([ + { + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'account2', + }, + ]), + ); + + expect(output).toEqual([ + { + host: 'custom.blob.core.windows.net', + endpoint: 'https://custom.blob.core.windows.net', + accountName: 'account2', + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }, + { + host: 'blob.core.windows.net', + endpoint: undefined, + accountName: undefined, + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }, + ]); + }); + + it('does not add default integration if blob.core.windows.net already exists', () => { + const output = readAzureBlobStorageIntegrationConfigs( + buildConfigs([ + { host: 'blob.core.windows.net', accountName: 'account1' }, + ]), + ); + expect(output).toEqual([ + { + host: 'blob.core.windows.net', + endpoint: undefined, + accountName: 'account1', + accountKey: undefined, + sasToken: undefined, + connectionString: undefined, + endpointSuffix: undefined, + aadCredential: undefined, + }, + ]); + }); +}); diff --git a/packages/integration/src/azureBlobStorage/config.ts b/packages/integration/src/azureBlobStorage/config.ts new file mode 100644 index 0000000000..10eccc252c --- /dev/null +++ b/packages/integration/src/azureBlobStorage/config.ts @@ -0,0 +1,170 @@ +/* + * 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 { Config } from '@backstage/config'; + +const AZURE_HOST = 'blob.core.windows.net'; + +/** + * The configuration parameters for a single Azure Blob Storage account. + * + * @public + */ +export type AzureBlobStorageIntegrationConfig = { + /** + * The name of the Azure Storage Account, e.g., "mystorageaccount". + */ + accountName?: string; + + /** + * The primary or secondary key for the Azure Storage Account. + * Only required if connectionString or SAS token are not specified. + */ + accountKey?: string; + + /** + * A Shared Access Signature (SAS) token for limited access to resources. + */ + sasToken?: string; + + /** + * A full connection string for the Azure Storage Account. + * This includes the account name, key, and endpoint details. + */ + connectionString?: string; + + /** + * Optional endpoint suffix for custom domains or sovereign clouds. + * e.g., "core.windows.net" for public Azure or "core.usgovcloudapi.net" for US Government cloud. + */ + endpointSuffix?: string; + + /** + * The host of the target that this matches on, e.g., "blob.core.windows.net". + */ + host: string; + + endpoint?: string; + /** + * Optional credential to use for Azure Active Directory authentication. + */ + aadCredential?: { + /** + * The client ID of the Azure AD application. + */ + clientId: string; + + /** + * The tenant ID for Azure AD. + */ + tenantId: string; + + /** + * The client secret for the Azure AD application. + */ + clientSecret: string; + }; +}; + +/** + * Reads a single Azure Blob Storage integration config. + * + * @param config - The config object of a single integration. + * @public + */ +export function readAzureBlobStorageIntegrationConfig( + config: Config, +): AzureBlobStorageIntegrationConfig { + const endpoint = config.getOptionalString('endpoint'); + const accountName = config.getString('accountName'); + const accountKey = config.getOptionalString('accountKey')?.trim(); + const sasToken = config.getOptionalString('sasToken')?.trim(); + const connectionString = config.getOptionalString('connectionString')?.trim(); + const endpointSuffix = config.getOptionalString('endpointSuffix')?.trim(); + + let host; + let pathname; + if (endpoint) { + try { + const url = new URL(endpoint); + host = url.host; + pathname = url.pathname; + } catch { + throw new Error( + `invalid azureBlobStorage integration config, endpoint '${endpoint}' is not a valid URL`, + ); + } + if (pathname !== '/') { + throw new Error( + `invalid azureBlobStorage integration config, endpoints cannot contain path, got '${endpoint}'`, + ); + } + } else { + host = AZURE_HOST; + } + const aadCredential = config.has('aadCredential') + ? { + clientId: config.getString('aadCredential.clientId'), + tenantId: config.getString('aadCredential.tenantId'), + clientSecret: config.getString('aadCredential.clientSecret')?.trim(), + } + : undefined; + + if (accountKey && sasToken) { + throw new Error( + `Invalid Azure Blob Storage config for ${accountName}: Both account key and SAS token cannot be used simultaneously.`, + ); + } + + if (aadCredential && (accountKey || sasToken)) { + throw new Error( + `Invalid Azure Blob Storage config for ${accountName}: Cannot use both Azure AD credentials and account keys/SAS tokens for the same account.`, + ); + } + + return { + host, + endpoint, + accountName, + accountKey, + sasToken, + connectionString, + endpointSuffix, + aadCredential, + }; +} + +/** + * Reads a set of Azure Blob Storage integration configs. + * + * @param configs - All of the integration config objects. + * @public + */ +export function readAzureBlobStorageIntegrationConfigs( + configs: Config[], +): AzureBlobStorageIntegrationConfig[] { + // First read all the explicit integrations + const result = configs.map(readAzureBlobStorageIntegrationConfig); + + // If no explicit blob.core.windows.net integration was added, put one in the list as + // a convenience + if (!result.some(c => c.host === AZURE_HOST)) { + result.push({ + host: AZURE_HOST, + }); + } + return result; +} diff --git a/plugins/kubernetes-backend/src/run.ts b/packages/integration/src/azureBlobStorage/index.ts similarity index 52% rename from plugins/kubernetes-backend/src/run.ts rename to packages/integration/src/azureBlobStorage/index.ts index b17ffa9d43..f55e9aaa79 100644 --- a/plugins/kubernetes-backend/src/run.ts +++ b/packages/integration/src/azureBlobStorage/index.ts @@ -13,21 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -import yn from 'yn'; -import { getRootLogger } from '@backstage/backend-common'; -import { startStandaloneServer } from './service/standaloneServer'; - -const port = process.env.PLUGIN_PORT ? Number(process.env.PLUGIN_PORT) : 3004; -const enableCors = yn(process.env.PLUGIN_CORS, { default: false }); -const logger = getRootLogger(); - -startStandaloneServer({ port, enableCors, logger }).catch(err => { - logger.error(err); - process.exit(1); -}); - -process.on('SIGINT', () => { - logger.info('CTRL+C pressed; exiting.'); - process.exit(0); -}); +export { AzureBlobStorageIntergation } from './AzureBlobStorageIntegration'; +export { + readAzureBlobStorageIntegrationConfig, + readAzureBlobStorageIntegrationConfigs, +} from './config'; +export type { AzureBlobStorageIntegrationConfig } from './config'; +export { DefaultAzureCredentialsManager } from './DefaultAzureCredentialsProvider'; +export type { AzureCredentialsManager } from './types'; diff --git a/packages/integration/src/azureBlobStorage/types.ts b/packages/integration/src/azureBlobStorage/types.ts new file mode 100644 index 0000000000..90c2725d05 --- /dev/null +++ b/packages/integration/src/azureBlobStorage/types.ts @@ -0,0 +1,35 @@ +/* + * 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 { TokenCredential } from '@azure/identity'; +import { + StorageSharedKeyCredential, + AnonymousCredential, +} from '@azure/storage-blob'; + +/** + * This allows implementations to be provided to retrieve Azure Storage accounts credentials. + * + * @public + * + */ +export interface AzureCredentialsManager { + getCredentials( + accountName: string, + ): Promise< + TokenCredential | StorageSharedKeyCredential | AnonymousCredential + >; +} diff --git a/packages/integration/src/index.ts b/packages/integration/src/index.ts index 32c573abef..a625f5d83c 100644 --- a/packages/integration/src/index.ts +++ b/packages/integration/src/index.ts @@ -22,6 +22,7 @@ export * from './awsS3'; export * from './awsCodeCommit'; +export * from './azureBlobStorage'; export * from './azure'; export * from './bitbucket'; export * from './bitbucketCloud'; diff --git a/packages/integration/src/registry.ts b/packages/integration/src/registry.ts index 7e4b34cc34..2e8111903b 100644 --- a/packages/integration/src/registry.ts +++ b/packages/integration/src/registry.ts @@ -26,6 +26,7 @@ import { GithubIntegration } from './github/GithubIntegration'; import { GitLabIntegration } from './gitlab/GitLabIntegration'; import { GiteaIntegration } from './gitea/GiteaIntegration'; import { HarnessIntegration } from './harness/HarnessIntegration'; +import { AzureBlobStorageIntergation } from './azureBlobStorage'; /** * Holds all registered SCM integrations, of all types. @@ -36,6 +37,7 @@ export interface ScmIntegrationRegistry extends ScmIntegrationsGroup { awsS3: ScmIntegrationsGroup; awsCodeCommit: ScmIntegrationsGroup; + azureBlobStorage: ScmIntegrationsGroup; azure: ScmIntegrationsGroup; /** * @deprecated in favor of `bitbucketCloud` and `bitbucketServer` diff --git a/packages/release-manifests/CHANGELOG.md b/packages/release-manifests/CHANGELOG.md index 2176118ea2..33042e37e8 100644 --- a/packages/release-manifests/CHANGELOG.md +++ b/packages/release-manifests/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/release-manifests +## 0.0.12-next.1 + +### Patch Changes + +- b29eaea: Allow overriding the fetch function used inside getManifestByVersion + +## 0.0.12-next.0 + +### Patch Changes + +- 2e140dc: Switch to native fetch for loading release manifests + ## 0.0.11 ### Patch Changes diff --git a/packages/release-manifests/package.json b/packages/release-manifests/package.json index 0b0e7e1591..b888d68e41 100644 --- a/packages/release-manifests/package.json +++ b/packages/release-manifests/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/release-manifests", - "version": "0.0.11", + "version": "0.0.12-next.1", "description": "Helper library for receiving release manifests", "backstage": { "role": "common-library" @@ -35,9 +35,6 @@ "postpack": "backstage-cli package postpack", "test": "backstage-cli package test" }, - "dependencies": { - "cross-fetch": "^4.0.0" - }, "devDependencies": { "@backstage/cli": "workspace:^", "@backstage/test-utils": "workspace:^", diff --git a/packages/release-manifests/report.api.md b/packages/release-manifests/report.api.md index 1ffa35838b..2d2cc00767 100644 --- a/packages/release-manifests/report.api.md +++ b/packages/release-manifests/report.api.md @@ -21,6 +21,12 @@ export function getManifestByVersion( // @public export type GetManifestByVersionOptions = { version: string; + fetch?: ( + url: string, + options?: { + signal?: AbortSignal; + }, + ) => Promise>; }; // @public diff --git a/packages/release-manifests/src/manifest.test.ts b/packages/release-manifests/src/manifest.test.ts index 3c7657a83f..ad5bf13496 100644 --- a/packages/release-manifests/src/manifest.test.ts +++ b/packages/release-manifests/src/manifest.test.ts @@ -55,6 +55,37 @@ describe('Release Manifests', () => { getManifestByVersion({ version: '999.0.1' }), ).rejects.toThrow('No release found for 999.0.1 version'); }); + + it('should allow overriding the fetch implementation', async () => { + const mockFetch = jest.fn().mockImplementation(async url => ({ + status: 200, + url, + json: () => ({ + packages: [{ name: '@backstage/core', version: '2.3.4' }], + }), + })); + + const pkgs = await getManifestByVersion({ + version: '0.0.0', + fetch: mockFetch, + }); + + expect(pkgs.packages).toEqual([ + { + name: '@backstage/core', + version: '2.3.4', + }, + ]); + + mockFetch.mockImplementation(async url => ({ + status: 404, + url, + })); + + await expect( + getManifestByVersion({ version: '0.0.0', fetch: mockFetch }), + ).rejects.toThrow('No release found for 0.0.0 version'); + }); }); describe('getManifestByReleaseLine', () => { diff --git a/packages/release-manifests/src/manifest.ts b/packages/release-manifests/src/manifest.ts index 004ccfc77c..66a5f62151 100644 --- a/packages/release-manifests/src/manifest.ts +++ b/packages/release-manifests/src/manifest.ts @@ -14,8 +14,6 @@ * limitations under the License. */ -import fetch from 'cross-fetch'; - const VERSIONS_BASE_URL = 'https://versions.backstage.io'; const GITHUB_RAW_BASE_URL = 'https://raw.githubusercontent.com/backstage/versions/main'; @@ -35,6 +33,10 @@ export type ReleaseManifest = { */ export type GetManifestByVersionOptions = { version: string; + fetch?: ( + url: string, + options?: { signal?: AbortSignal }, + ) => Promise>; }; // Wait for waitMs, or until signal is aborted. @@ -84,15 +86,21 @@ export async function getManifestByVersion( options: GetManifestByVersionOptions, ): Promise { const versionEnc = encodeURIComponent(options.version); + + const fetchFn = options.fetch ?? fetch; + const res = await withFallback( signal => - fetch(`${VERSIONS_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { + fetchFn(`${VERSIONS_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { signal, }), signal => - fetch(`${GITHUB_RAW_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, { - signal, - }), + fetchFn( + `${GITHUB_RAW_BASE_URL}/v1/releases/${versionEnc}/manifest.json`, + { + signal, + }, + ), 500, ); if (res.status === 404) { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index dad8d3c052..8756efb2d9 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/repo-tools +## 0.12.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/cli-node@0.2.11-next.1 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + +## 0.12.0-next.1 + +### Patch Changes + +- 860e3b5: Generated OpenAPI clients now support paths with tags. +- 00058d0: The `generate-patch` command will now add a single resolution entry for all versions of the patched package, rather than separate entries for each version query. +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/errors@1.2.5 + +## 0.12.0-next.0 + +### Minor Changes + +- c1eccd6: Fix invalid path and malformed flags bugs in api-reports.ts + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/cli-node@0.2.11-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + +## 0.11.0 + +### Minor Changes + +- 1440232: `backstage-repo-tools package schema openapi generate --server` now generates complete TS interfaces for all request/response objects in your OpenAPI schema. This fixes an edge case around recursive schemas and standardizes both the generated client and server to have similar generated types. +- 47fdbb4: Adds a `--watch` mode to the `schema openapi generate` command for a better local schema writing experience. + +### Patch Changes + +- 95401a8: The `generate-patch` command now properly includes newly created files in the patch. +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. +- 3f1fb21: The `generate-patch` command will now fall back to always adding a `resolutions` entry, even if no matching descriptors are found. +- dde85ee: Added a new `generate-patch` command that can be used to generate patches for current changes in a source workspace to be installed it a target workspace. +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-node@0.2.10 + - @backstage/errors@1.2.5 + ## 0.11.0-next.3 ### Patch Changes diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index de4161d688..c42a49109e 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/repo-tools", - "version": "0.11.0-next.3", + "version": "0.12.0-next.2", "description": "CLI for Backstage repo tooling ", "backstage": { "role": "cli" diff --git a/packages/repo-tools/src/commands/api-reports/api-reports.test.ts b/packages/repo-tools/src/commands/api-reports/api-reports.test.ts index 955720c52e..94ae42d715 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports.test.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports.test.ts @@ -323,6 +323,24 @@ describe('buildApiReports', () => { expect(buildDocs).not.toHaveBeenCalled(); }); + it('should throw an error if a path does not exist', async () => { + const paths = ['packages/package-a', 'packages/package-c']; + const opts = {}; + + await expect(buildApiReports(paths, opts)).rejects.toThrow( + 'Invalid paths provided: packages/package-c', + ); + }); + it('should throw an error if an option is malformed', async () => { + const paths = ['ae-undocumented']; + const opts = { + omitMessages: 'ae-wrong-input-file-type,', + }; + + await expect(buildApiReports(paths, opts)).rejects.toThrow( + 'Invalid paths provided: ae-undocumented', + ); + }); }); describe('allowWarnings', () => { it('should accept single path value', async () => { diff --git a/packages/repo-tools/src/commands/api-reports/api-reports.ts b/packages/repo-tools/src/commands/api-reports/api-reports.ts index 637cd86671..4e568102d9 100644 --- a/packages/repo-tools/src/commands/api-reports/api-reports.ts +++ b/packages/repo-tools/src/commands/api-reports/api-reports.ts @@ -48,6 +48,7 @@ export const buildApiReports = async (paths: string[] = [], opts: Options) => { const omitMessages = parseArrayOption(opts.omitMessages); const isAllPackages = !paths?.length; + const selectedPackageDirs = await resolvePackagePaths({ paths, include: opts.include, @@ -130,5 +131,10 @@ export const buildApiReports = async (paths: string[] = [], opts: Options) => { * // returns [] */ function parseArrayOption(value: string | undefined) { - return value ? value.split(',').map(s => s.trim()) : []; + return value + ? value + .split(',') + .map(s => s.trim()) + .filter(Boolean) + : []; } diff --git a/packages/repo-tools/src/commands/generate-patch/generate-patch.ts b/packages/repo-tools/src/commands/generate-patch/generate-patch.ts index e817abd74b..224b7ae4e6 100644 --- a/packages/repo-tools/src/commands/generate-patch/generate-patch.ts +++ b/packages/repo-tools/src/commands/generate-patch/generate-patch.ts @@ -182,8 +182,6 @@ async function loadTrimmedRootPkg(ctx: PatchContext, query?: string) { }; } - const resolutionMap = await readResolutionMap(ctx); - // Any existing resolution entries for the package are removed const entriesToRemove = Object.entries(resolutionsObj).filter(([key]) => key.startsWith(`${ctx.packageName}@`), @@ -201,29 +199,9 @@ async function loadTrimmedRootPkg(ctx: PatchContext, query?: string) { } } - // This collects the list of version descriptors that we want to apply the patch to - const descriptors = new Array(); - for (const [descriptor, locator] of resolutionMap) { - // Skip virtual and other non-npm entries - if (!locator.includes('@npm:')) { - // We know that virtual entries are fine to skip, but want to warn if we skip others - if (!locator.includes('@virtual:')) { - console.warn(`Skipping resolution for ${descriptor}, no version found`); - } - continue; - } - - descriptors.push(descriptor); - } - return async (patchEntry?: string) => { - if (descriptors.length > 0) { - for (const descriptor of descriptors) { - resolutionsObj[descriptor] = patchEntry; - } - } else { - resolutionsObj[ctx.packageName] = patchEntry; - } + resolutionsObj[ctx.packageName] = patchEntry; + // We use the same patch for all versions of the package, if they don't // apply it might require manual intervention using the --query option await fs.writeJson( @@ -297,41 +275,6 @@ function tryParsePatchResolution(value?: string): string | undefined { return patchFilePath; } -// Read out the descriptors for all entries of the package in the target repo -async function readResolutionMap( - ctx: PatchContext, -): Promise> { - const { stdout: whyOutput } = await exec( - 'yarn', - ['why', '--json', ctx.packageName], - { - cwd: ctx.targetRoot, - maxBuffer: 64 * 1024 * 1024, - }, - ); - - const resolutionMap = new Map(); - - for (const line of whyOutput.toString('utf8').trim().split(/\r?\n/)) { - for (const { locator, descriptor } of Object.values( - JSON.parse(line).children, - ) as Array<{ locator: string; descriptor: string }>) { - const existing = resolutionMap.get(descriptor); - if (existing) { - if (existing !== locator) { - throw new Error( - `Conflicting resolutions in target package for ${descriptor}: ${existing} vs ${locator}`, - ); - } - } else { - resolutionMap.set(descriptor, locator); - } - } - } - - return resolutionMap; -} - // Build and pack the source package to an archive in the work directory async function buildTargetArchive(ctx: PatchContext): Promise { await exec('yarn', ['build'], { diff --git a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts index bd8ff8530e..edcb49a9be 100644 --- a/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts +++ b/packages/repo-tools/src/commands/package/schema/openapi/generate/client.ts @@ -21,11 +21,13 @@ import { OUTPUT_PATH, } from '../../../../../lib/openapi/constants'; import { paths as cliPaths } from '../../../../../lib/paths'; -import { mkdirpSync } from 'fs-extra'; import fs from 'fs-extra'; import { exec } from '../../../../../lib/exec'; import { resolvePackagePath } from '@backstage/backend-plugin-api'; -import { getPathToCurrentOpenApiSpec } from '../../../../../lib/openapi/helpers'; +import { + getPathToCurrentOpenApiSpec, + toGeneratorAdditionalProperties, +} from '../../../../../lib/openapi/helpers'; async function generate( outputDirectory: string, @@ -37,12 +39,11 @@ async function generate( outputDirectory, OUTPUT_PATH, ); - const additionalProperties = clientAdditionalProperties - ? `--additional-properties=${clientAdditionalProperties}` - : ''; - mkdirpSync(resolvedOutputDirectory); + const additionalProperties = toGeneratorAdditionalProperties({ + initialValue: clientAdditionalProperties, + }); - await fs.mkdirp(resolvedOutputDirectory); + await fs.emptyDir(resolvedOutputDirectory); await fs.writeFile( resolve(resolvedOutputDirectory, '.openapi-generator-ignore'), @@ -67,7 +68,9 @@ async function generate( ), '--generator-key', 'v3.0', - additionalProperties, + additionalProperties + ? `--additional-properties=${additionalProperties}` + : '', ], { signal: abortSignal?.signal, 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 1fbc42c175..8c342b0a68 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 @@ -86,7 +86,7 @@ async function generate(abortSignal?: AbortController) { const resolvedOpenapiPath = await getPathToCurrentOpenApiSpec(); const resolvedOutputDirectory = await getRelativePathToFile(OUTPUT_PATH); - await fs.mkdirp(resolvedOutputDirectory); + await fs.emptyDir(resolvedOutputDirectory); await fs.writeFile( resolve(resolvedOutputDirectory, '.openapi-generator-ignore'), diff --git a/packages/repo-tools/src/lib/openapi/helpers.ts b/packages/repo-tools/src/lib/openapi/helpers.ts index 2359a1bbb0..868623b874 100644 --- a/packages/repo-tools/src/lib/openapi/helpers.ts +++ b/packages/repo-tools/src/lib/openapi/helpers.ts @@ -51,3 +51,23 @@ export async function loadAndValidateOpenApiYaml(path: string) { await Parser.validate(cloneDeep(yaml) as any); return yaml; } + +export function toGeneratorAdditionalProperties({ + initialValue, + defaultValue, +}: { + initialValue?: string; + defaultValue?: Record; +}) { + const items = initialValue?.split(',') ?? []; + const parsed = items.reduce( + (acc, item) => { + const [key, value] = item.split('='); + return { ...acc, [key]: value }; + }, + { ...defaultValue }, + ); + return Object.entries(parsed) + .map(([key, value]) => `${key}=${value}`) + .join(','); +} diff --git a/packages/repo-tools/src/lib/paths.ts b/packages/repo-tools/src/lib/paths.ts index 96fc92f035..0dcec32ff1 100644 --- a/packages/repo-tools/src/lib/paths.ts +++ b/packages/repo-tools/src/lib/paths.ts @@ -36,6 +36,23 @@ export async function resolvePackagePaths( const { paths: providedPaths, include, exclude } = options; let packages = await PackageGraph.listTargetPackages(); + if (providedPaths && providedPaths.length > 0) { + const invalidPaths: string[] = []; + for (const path of providedPaths) { + const matches = packages.some( + ({ dir }) => + new Minimatch(path).match(relativePath(paths.targetRoot, dir)) || + isChildPath(dir, path), + ); + if (!matches) { + invalidPaths.push(path); + } + } + if (invalidPaths.length > 0) { + throw new Error(`Invalid paths provided: ${invalidPaths.join(', ')}`); + } + } + if (providedPaths && providedPaths.length > 0) { packages = packages.filter(({ dir }) => providedPaths.some( diff --git a/packages/repo-tools/templates/typescript-backstage-client.yaml b/packages/repo-tools/templates/typescript-backstage-client.yaml index 785ffde881..dc3220f2cd 100644 --- a/packages/repo-tools/templates/typescript-backstage-client.yaml +++ b/packages/repo-tools/templates/typescript-backstage-client.yaml @@ -1,10 +1,6 @@ templateDir: templates/typescript-backstage-client files: - api.mustache: - templateType: API - # For some reason, they check for destinationFilename differences. We have to change the ending to override the file. - destinationFilename: .client.ts model.mustache: templateType: Model destinationFilename: .model.ts @@ -32,6 +28,9 @@ files: apis/index.mustache: templateType: SupportingFiles destinationFilename: apis/index.ts + apis/api-all.mustache: + templateType: SupportingFiles + destinationFilename: apis/Api.client.ts pluginId.mustache: templateType: SupportingFiles destinationFilename: pluginId.ts diff --git a/packages/repo-tools/templates/typescript-backstage-client/api.mustache b/packages/repo-tools/templates/typescript-backstage-client/apis/api-all.mustache similarity index 95% rename from packages/repo-tools/templates/typescript-backstage-client/api.mustache rename to packages/repo-tools/templates/typescript-backstage-client/apis/api-all.mustache index ee8ea4d17e..edf2e55a36 100644 --- a/packages/repo-tools/templates/typescript-backstage-client/api.mustache +++ b/packages/repo-tools/templates/typescript-backstage-client/apis/api-all.mustache @@ -4,10 +4,12 @@ import { FetchApi } from '../types/fetch'; import crossFetch from 'cross-fetch'; import {pluginId} from '../pluginId'; import * as parser from 'uri-template'; - +{{#apiInfo}} +{{#apis}} {{#imports}} import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; {{/imports}} +{{/apis}} /** * Wraps the Response type to convey a type on the json call. @@ -18,8 +20,6 @@ export type TypedResponse = Omit & { json: () => Promise; }; -{{#operations}} - /** * Options you can pass into a request for additional information. * @@ -28,7 +28,8 @@ export type TypedResponse = Omit & { export interface RequestOptions { token?: string; } - +{{#apis}} +{{#operations}} {{#operation}} /** * @public @@ -62,12 +63,13 @@ export type {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}} = { {{/hasHeaderParams}} } {{/operation}} +{{/operations}} +{{/apis}} /** - * {{{description}}}{{^description}}no description{{/description}} * @public */ -export class {{classname}}Client { +export class DefaultApiClient { private readonly discoveryApi: DiscoveryApi; private readonly fetchApi: FetchApi; @@ -79,6 +81,9 @@ export class {{classname}}Client { this.fetchApi = options.fetchApi || { fetch: crossFetch }; } + {{#apis}} + {{#operations}} + {{#operation}} /** {{#notes}} @@ -123,5 +128,7 @@ export class {{classname}}Client { } {{/operation}} + {{/operations}} + {{/apis}} } -{{/operations}} +{{/apiInfo}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage-client/apis/index.mustache b/packages/repo-tools/templates/typescript-backstage-client/apis/index.mustache index 4c8996c5ee..ec61c280a8 100644 --- a/packages/repo-tools/templates/typescript-backstage-client/apis/index.mustache +++ b/packages/repo-tools/templates/typescript-backstage-client/apis/index.mustache @@ -1,3 +1,3 @@ // -export * from './DefaultApi.client'; +export * from './Api.client'; diff --git a/packages/repo-tools/templates/typescript-backstage-server.yaml b/packages/repo-tools/templates/typescript-backstage-server.yaml index e9140d0bc6..59d6c07c10 100644 --- a/packages/repo-tools/templates/typescript-backstage-server.yaml +++ b/packages/repo-tools/templates/typescript-backstage-server.yaml @@ -1,13 +1,12 @@ templateDir: templates/typescript-backstage-server files: - api.mustache: - templateType: API - # For some reason, they check for destinationFilename differences. We have to change the ending to override the file. - destinationFilename: .server.ts apis/index.mustache: templateType: SupportingFiles destinationFilename: apis/index.ts + apis/api-all.mustache: + templateType: SupportingFiles + destinationFilename: apis/Api.server.ts index.mustache: templateType: SupportingFiles destinationFilename: index.ts diff --git a/packages/repo-tools/templates/typescript-backstage-server/api.mustache b/packages/repo-tools/templates/typescript-backstage-server/apis/api-all.mustache similarity index 91% rename from packages/repo-tools/templates/typescript-backstage-server/api.mustache rename to packages/repo-tools/templates/typescript-backstage-server/apis/api-all.mustache index fd27bb94fa..30770d6481 100644 --- a/packages/repo-tools/templates/typescript-backstage-server/api.mustache +++ b/packages/repo-tools/templates/typescript-backstage-server/apis/api-all.mustache @@ -1,4 +1,7 @@ +// {{>licenseInfo}} +{{#apiInfo}} +{{#apis}} {{#imports}} import { {{classname}} } from '{{filename}}.model{{importFileExtension}}'; {{/imports}} @@ -39,16 +42,19 @@ export type {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}} = { response: {{#responses}} {{{dataType}}}{{^dataType}}void{{/dataType}} {{^-last}} | {{/-last}} {{/responses}} } {{/operation}} - -/** - * {{{description}}}{{^description}}no description{{/description}} - */ +{{/operations}} +{{/apis}} export type EndpointMap = { + {{#apis}} + {{#operations}} {{#operation}} '#{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}|{{path}}': {{#lambda.pascalcase}}{{nickname}}{{/lambda.pascalcase}}, {{/operation}} + {{/operations}} + {{/apis}} } -{{/operations}} + +{{/apiInfo}} \ No newline at end of file diff --git a/packages/repo-tools/templates/typescript-backstage-server/apis/index.mustache b/packages/repo-tools/templates/typescript-backstage-server/apis/index.mustache index d0638a7538..fb39a63a46 100644 --- a/packages/repo-tools/templates/typescript-backstage-server/apis/index.mustache +++ b/packages/repo-tools/templates/typescript-backstage-server/apis/index.mustache @@ -1,3 +1,4 @@ // +{{>licenseInfo}} -export * from './DefaultApi.server'; +export * from './Api.server' \ No newline at end of file diff --git a/packages/scaffolder-internal/CHANGELOG.md b/packages/scaffolder-internal/CHANGELOG.md index 06d7a77dc9..8a2df052a6 100644 --- a/packages/scaffolder-internal/CHANGELOG.md +++ b/packages/scaffolder-internal/CHANGELOG.md @@ -1,5 +1,36 @@ # @internal/scaffolder +## 0.0.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## 0.0.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## 0.0.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-react@1.14.0 + ## 0.0.3-next.3 ### Patch Changes diff --git a/packages/scaffolder-internal/package.json b/packages/scaffolder-internal/package.json index 576df6f587..cf458bd536 100644 --- a/packages/scaffolder-internal/package.json +++ b/packages/scaffolder-internal/package.json @@ -1,6 +1,6 @@ { "name": "@internal/scaffolder", - "version": "0.0.3-next.3", + "version": "0.0.4-next.2", "backstage": { "role": "web-library", "inline": true @@ -23,6 +23,7 @@ "test": "backstage-cli package test" }, "dependencies": { + "@backstage/frontend-plugin-api": "workspace:^", "@backstage/plugin-scaffolder-react": "workspace:^", "zod": "^3.22.4" }, diff --git a/packages/scaffolder-internal/src/wiring/InternalFormDecorator.ts b/packages/scaffolder-internal/src/wiring/InternalFormDecorator.ts new file mode 100644 index 0000000000..7942544acb --- /dev/null +++ b/packages/scaffolder-internal/src/wiring/InternalFormDecorator.ts @@ -0,0 +1,42 @@ +/* + * 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 { OpaqueType } from '@internal/opaque'; +import { z } from 'zod'; + +import { + ScaffolderFormDecorator, + ScaffolderFormDecoratorContext, +} from '@backstage/plugin-scaffolder-react/alpha'; +import { AnyApiRef } from '@backstage/frontend-plugin-api'; + +/** @alpha */ +export const OpaqueFormDecorator = OpaqueType.create<{ + public: ScaffolderFormDecorator; + versions: { + readonly version: 'v1'; + readonly id: string; + readonly schema?: { + input?: { + [key in string]: (zImpl: typeof z) => z.ZodType; + }; + }; + readonly deps?: { [key in string]: AnyApiRef }; + readonly decorator: ( + ctx: ScaffolderFormDecoratorContext, + deps: { [depName in string]: AnyApiRef['T'] }, + ) => Promise; + }; +}>({ type: '@backstage/scaffolder/FormDecorator', versions: ['v1'] }); diff --git a/packages/scaffolder-internal/src/wiring/index.ts b/packages/scaffolder-internal/src/wiring/index.ts index c85755bccf..37c8bd09cb 100644 --- a/packages/scaffolder-internal/src/wiring/index.ts +++ b/packages/scaffolder-internal/src/wiring/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { OpaqueFormField, type FormField } from './InternalFormField'; +export { OpaqueFormDecorator } from './InternalFormDecorator'; diff --git a/packages/techdocs-cli-embedded-app/CHANGELOG.md b/packages/techdocs-cli-embedded-app/CHANGELOG.md index 8b808176b3..bee2276582 100644 --- a/packages/techdocs-cli-embedded-app/CHANGELOG.md +++ b/packages/techdocs-cli-embedded-app/CHANGELOG.md @@ -1,5 +1,81 @@ # techdocs-cli-embedded-app +## 0.2.103-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/cli@0.29.3-next.2 + - @backstage/app-defaults@1.5.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/test-utils@1.7.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.2 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## 0.2.103-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/plugin-techdocs@1.11.3-next.1 + - @backstage/app-defaults@1.5.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## 0.2.103-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.3-next.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-techdocs@1.11.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/app-defaults@1.5.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/test-utils@1.7.3-next.0 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## 0.2.102 + +### Patch Changes + +- Updated dependencies + - @backstage/cli@0.29.0 + - @backstage/plugin-catalog@1.25.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-techdocs@1.11.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-app-api@1.15.2 + - @backstage/app-defaults@1.5.13 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.1 + - @backstage/test-utils@1.7.1 + ## 0.2.102-next.3 ### Patch Changes diff --git a/packages/techdocs-cli-embedded-app/package.json b/packages/techdocs-cli-embedded-app/package.json index 223a2b1282..5d3add528a 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.102-next.3", + "version": "0.2.103-next.2", "backstage": { "role": "frontend" }, @@ -30,7 +30,7 @@ "last 1 safari version" ] }, - "prettier": "@spotify/prettier-config", + "prettier": "@backstage/cli/config/prettier", "dependencies": { "@backstage/app-defaults": "workspace:^", "@backstage/catalog-model": "workspace:^", diff --git a/packages/techdocs-cli/CHANGELOG.md b/packages/techdocs-cli/CHANGELOG.md index fa38374cbf..95b03dab88 100644 --- a/packages/techdocs-cli/CHANGELOG.md +++ b/packages/techdocs-cli/CHANGELOG.md @@ -1,5 +1,50 @@ # @techdocs/cli +## 1.8.24-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-techdocs-node@1.12.15-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + +## 1.8.24-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/plugin-techdocs-node@1.12.15-next.1 + +## 1.8.24-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/plugin-techdocs-node@1.12.15-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + +## 1.8.22 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/cli-common@0.1.15 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-techdocs-node@1.12.13 + ## 1.8.22-next.3 ### Patch Changes diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json index 2069ace552..da16a96f22 100644 --- a/packages/techdocs-cli/package.json +++ b/packages/techdocs-cli/package.json @@ -1,6 +1,6 @@ { "name": "@techdocs/cli", - "version": "1.8.22-next.3", + "version": "1.8.24-next.2", "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 fe36d960a3..acce745e15 100644 --- a/packages/test-utils/CHANGELOG.md +++ b/packages/test-utils/CHANGELOG.md @@ -1,5 +1,44 @@ # @backstage/test-utils +## 1.7.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 1.7.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## 1.7.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-app-api@1.15.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-permission-react@0.4.28 + ## 1.7.1-next.0 ### Patch Changes diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 6edcf0b0b4..dc3a688026 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/test-utils", - "version": "1.7.1-next.0", + "version": "1.7.3-next.1", "description": "Utilities to test Backstage plugins and apps.", "backstage": { "role": "web-library" diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md index 3a52dd85af..bf58f00548 100644 --- a/packages/theme/CHANGELOG.md +++ b/packages/theme/CHANGELOG.md @@ -1,5 +1,17 @@ # @backstage/theme +## 0.6.3-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. + +## 0.6.1 + +### Patch Changes + +- ea75c37: Internal refactor to avoid top-level imports from MUI. + ## 0.6.1-next.0 ### Patch Changes diff --git a/packages/theme/package.json b/packages/theme/package.json index 7e52e6a6ad..f30561bf91 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/theme", - "version": "0.6.1-next.0", + "version": "0.6.3-next.0", "description": "material-ui theme for use with Backstage.", "backstage": { "role": "web-library" diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index c8b9243adb..c7980abd94 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,5 +1,11 @@ # @backstage/types +## 1.2.0 + +### Minor Changes + +- c5e39e7: Introduce `createDeferred` and `DeferredPromise`. + ## 1.1.1 ### Patch Changes diff --git a/packages/types/package.json b/packages/types/package.json index 2402dc84fa..efbc62a9a2 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/types", - "version": "1.1.1", + "version": "1.2.0", "description": "Common TypeScript types used within Backstage", "backstage": { "role": "common-library" diff --git a/packages/yarn-plugin/CHANGELOG.md b/packages/yarn-plugin/CHANGELOG.md index b49ca12258..24f0a41354 100644 --- a/packages/yarn-plugin/CHANGELOG.md +++ b/packages/yarn-plugin/CHANGELOG.md @@ -1,9 +1,41 @@ # yarn-plugin-backstage +## 0.0.4-next.1 + +### Patch Changes + +- 48cc7c5: Use yarn's built-in http utilities for fetching release manifests +- Updated dependencies + - @backstage/release-manifests@0.0.12-next.1 + - @backstage/cli-common@0.1.15 + +## 0.0.4-next.0 + +### Patch Changes + +- 27600c2: Verify type of `beforeWorkspacePacking` hook signature +- d8bd6f5: Cherry-pick lodash method to reduce bundle size +- 344c591: Use native `Array.some` instead of lodash to reduce bundle size +- 9296a33: Remove dependency on `chalk` to reduce bundle size +- 9017481: Move Backstage version to parameter in bound descriptor for better + compatibility with third-party lockfile parsing tools +- Updated dependencies + - @backstage/release-manifests@0.0.12-next.0 + - @backstage/cli-common@0.1.15 + +## 0.0.3 + +### Patch Changes + +- Updated dependencies + - @backstage/cli-common@0.1.15 + - @backstage/release-manifests@0.0.11 + ## 0.0.3-next.0 ### Patch Changes +- aba538d: Do not throw when descriptors are already bound in bindDescriptor - Updated dependencies - @backstage/cli-common@0.1.15-next.0 - @backstage/release-manifests@0.0.11 @@ -12,6 +44,9 @@ ### Patch Changes +- a8bd401: Validate version of yarn in plugin to ensure compatibility +- b207f69: Memoize fetching of release manifest +- 9e29186: Ensure plugin works correctly when running yarn dedupe - bd32d5a: Add additional check before packing workspace to verify that all backstage:^ versions have been removed. - Updated dependencies - @backstage/cli-common@0.1.14 @@ -29,6 +64,7 @@ ### Patch Changes +- Initial release - Updated dependencies - @backstage/cli-common@0.1.14-next.0 - @backstage/release-manifests@0.0.11 diff --git a/packages/yarn-plugin/package.json b/packages/yarn-plugin/package.json index 31879ee56f..bca6fed42f 100644 --- a/packages/yarn-plugin/package.json +++ b/packages/yarn-plugin/package.json @@ -1,6 +1,6 @@ { "name": "yarn-plugin-backstage", - "version": "0.0.3-next.0", + "version": "0.0.4-next.1", "description": "Yarn plugin for working with Backstage monorepos", "backstage": { "role": "node-library" @@ -34,8 +34,7 @@ "@backstage/release-manifests": "workspace:^", "@yarnpkg/core": "^4.0.3", "@yarnpkg/fslib": "^3.0.2", - "chalk": "^4.0.0", - "lodash": "^4.17.21", + "@yarnpkg/plugin-pack": "^4.0.0", "semver": "^7.6.0" }, "devDependencies": { diff --git a/packages/yarn-plugin/report.api.md b/packages/yarn-plugin/report.api.md index f0300ec9a1..928703ed3e 100644 --- a/packages/yarn-plugin/report.api.md +++ b/packages/yarn-plugin/report.api.md @@ -3,9 +3,10 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { Hooks } 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/beforeWorkspacePacking.test.ts b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.test.ts index d156182923..ee4af2c4f6 100644 --- a/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.test.ts +++ b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.test.ts @@ -14,35 +14,24 @@ * limitations under the License. */ -import { Manifest, Workspace } from '@yarnpkg/core'; +import { + Configuration, + Manifest, + Project, + Workspace, + httpUtils, +} from '@yarnpkg/core'; import { npath, ppath } from '@yarnpkg/fslib'; import { createMockDirectory } from '@backstage/backend-test-utils'; import { beforeWorkspacePacking } from './beforeWorkspacePacking'; -jest.mock('@backstage/release-manifests', () => ({ - getManifestByVersion: jest.fn().mockResolvedValue({ - releaseVersion: '1.23.45', - packages: [ - { - name: '@backstage/core', - version: '3.2.1', - }, - { - name: '@backstage/plugin-1', - version: '6.5.4', - }, - { - name: '@backstage/plugin-2', - version: '9.8.7', - }, - ], - }), -})); - const makeWorkspace = (manifest: object) => { return { manifest: Manifest.fromText(JSON.stringify(manifest)), + project: new Project(ppath.cwd(), { + configuration: Configuration.create(ppath.cwd()), + }), } as Workspace; }; @@ -58,6 +47,24 @@ describe('beforeWorkspacePacking', () => { .spyOn(process, 'cwd') .mockReturnValue(npath.toPortablePath(mockDir.path)); + jest.spyOn(httpUtils, 'get').mockResolvedValue({ + releaseVersion: '1.23.45', + packages: [ + { + name: '@backstage/core', + version: '3.2.1', + }, + { + name: '@backstage/plugin-1', + version: '6.5.4', + }, + { + name: '@backstage/plugin-2', + version: '9.8.7', + }, + ], + }); + mockDir.setContent({ 'backstage.json': JSON.stringify({ version: '1.23.45', diff --git a/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts index 41014a55a6..e5823607e3 100644 --- a/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts +++ b/packages/yarn-plugin/src/handlers/beforeWorkspacePacking.ts @@ -15,8 +15,11 @@ */ import { Descriptor, Workspace, structUtils } from '@yarnpkg/core'; -import { some } from 'lodash'; -import { getCurrentBackstageVersion, getPackageVersion } from '../util'; +import { + bindBackstageVersion, + getCurrentBackstageVersion, + getPackageVersion, +} from '../util'; import { PROTOCOL } from '../constants'; const hasBackstageVersion = (range: string) => @@ -66,18 +69,18 @@ export const beforeWorkspacePacking = async ( ); rawManifest[finalDependencyType][ident] = `^${await getPackageVersion( - structUtils.makeDescriptor( - descriptor, - `${PROTOCOL}${backstageVersion}`, - ), + bindBackstageVersion(descriptor, backstageVersion), + workspace.project.configuration, )}`; } } if ( - some( - ['dependencies', 'devDependencies', 'optionalDependencies'], - dependencyType => some(rawManifest[dependencyType], hasBackstageVersion), + ['dependencies', 'devDependencies', 'optionalDependencies'].some( + dependencyType => + Object.values(rawManifest[dependencyType] ?? {}).some( + hasBackstageVersion, + ), ) ) { throw new Error( diff --git a/packages/yarn-plugin/src/index.ts b/packages/yarn-plugin/src/index.ts index f548463829..9c20e9a45c 100644 --- a/packages/yarn-plugin/src/index.ts +++ b/packages/yarn-plugin/src/index.ts @@ -22,16 +22,21 @@ */ import { Plugin, semverUtils, YarnVersion } from '@yarnpkg/core'; -import chalk from 'chalk'; +import { Hooks } from '@yarnpkg/plugin-pack'; import { beforeWorkspacePacking } from './handlers/beforeWorkspacePacking'; import { BackstageResolver } from './resolver/BackstageResolver'; +// All dependencies of the yarn plugin are bundled during the build. Chalk +// triples the size of the plugin bundle when included, so we avoid the +// dependency by hard-coding the ANSI escape codes for the one bit of formatting +// we need. +const RED_BOLD = `\u001B[31;1m`; +const RESET = '\u001B[0m'; + if (!semverUtils.satisfiesWithPrereleases(YarnVersion, '^4.1.1')) { console.error(); console.error( - `${chalk.bold.red( - 'Unsupported yarn version.', - )}: The Backstage yarn plugin only works with yarn ^4.1.1. Please upgrade yarn, or remove this plugin with "yarn plugin remove @yarnpkg/plugin-backstage".`, + `${RED_BOLD}Unsupported yarn version${RESET}: The Backstage yarn plugin only works with yarn ^4.1.1. Please upgrade yarn, or remove this plugin with "yarn plugin remove @yarnpkg/plugin-backstage".`, ); console.error(); } @@ -39,7 +44,7 @@ if (!semverUtils.satisfiesWithPrereleases(YarnVersion, '^4.1.1')) { /** * @public */ -const plugin: Plugin = { +const plugin: Plugin = { hooks: { beforeWorkspacePacking, }, diff --git a/packages/yarn-plugin/src/resolver/BackstageResolver.test.ts b/packages/yarn-plugin/src/resolver/BackstageResolver.test.ts index d7d9126923..8cba189cb8 100644 --- a/packages/yarn-plugin/src/resolver/BackstageResolver.test.ts +++ b/packages/yarn-plugin/src/resolver/BackstageResolver.test.ts @@ -14,31 +14,22 @@ * limitations under the License. */ -import { structUtils } from '@yarnpkg/core'; +import { + Configuration, + Project, + ResolveOptions, + structUtils, + ThrowReport, + httpUtils, +} from '@yarnpkg/core'; import { npath, ppath } from '@yarnpkg/fslib'; -import { getManifestByVersion } from '@backstage/release-manifests'; import { BackstageResolver } from './BackstageResolver'; import { createMockDirectory } from '@backstage/backend-test-utils'; -jest.mock('@backstage/release-manifests', () => ({ - getManifestByVersion: jest.fn().mockResolvedValue({ - releaseVersion: '1.23.45', - packages: [ - { - name: '@backstage/core', - version: '6.7.8', - }, - ], - }), -})); - -const getManifestByVersionMock = getManifestByVersion as jest.MockedFunction< - typeof getManifestByVersion ->; - describe('BackstageResolver', () => { const mockDir = createMockDirectory(); let backstageResolver: BackstageResolver; + let resolveOptions: ResolveOptions; beforeEach(() => { jest @@ -49,6 +40,16 @@ describe('BackstageResolver', () => { .spyOn(process, 'cwd') .mockReturnValue(npath.toPortablePath(mockDir.path)); + jest.spyOn(httpUtils, 'get').mockResolvedValue({ + releaseVersion: '1.23.45', + packages: [ + { + name: '@backstage/core', + version: '6.7.8', + }, + ], + }); + mockDir.setContent({ 'backstage.json': JSON.stringify({ version: '1.23.45', @@ -71,6 +72,14 @@ describe('BackstageResolver', () => { }); backstageResolver = new BackstageResolver(); + + resolveOptions = { + resolver: backstageResolver, + project: new Project(ppath.cwd(), { + configuration: Configuration.create(ppath.cwd()), + }), + report: new ThrowReport(), + }; }); afterEach(() => { @@ -96,7 +105,7 @@ describe('BackstageResolver', () => { describe('bindDescriptor', () => { describe('with range "backstage:^"', () => { - it('returns a descriptor basedwith a version range for the current Backstage version', () => { + it('returns a descriptor with a version range for the current Backstage version', () => { expect( backstageResolver.bindDescriptor( structUtils.makeDescriptor( @@ -107,25 +116,25 @@ describe('BackstageResolver', () => { ).toEqual( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ), ); }); }); - describe('with range "backstage:1.23.45"', () => { + describe('with range "backstage:^::v=1.23.45"', () => { it('returns the correct descriptor', () => { expect( backstageResolver.bindDescriptor( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ), ), ).toEqual( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ), ); }); @@ -136,11 +145,11 @@ describe('BackstageResolver', () => { it('returns an npm: descriptor based on the manifest for the appropriate backstage version', async () => { const descriptor = structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ); await expect( - backstageResolver.getCandidates(descriptor), + backstageResolver.getCandidates(descriptor, {}, resolveOptions), ).resolves.toEqual([structUtils.makeLocator(descriptor, 'npm:6.7.8')]); }); @@ -151,66 +160,57 @@ describe('BackstageResolver', () => { structUtils.makeIdent('backstage', 'core'), 'npm:1.2.3', ), + {}, + resolveOptions, ), ).rejects.toThrow(/unsupported version protocol/i); }); - it('rejects backstage: ranges with a ^ shorthand version', async () => { + it('rejects backstage: ranges missing a version parameter', async () => { await expect( backstageResolver.getCandidates( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), 'backstage:^', ), + {}, + resolveOptions, ), - ).rejects.toThrow(/invalid backstage version/i); + ).rejects.toThrow(/missing Backstage version/i); }); - it('rejects backstage: ranges with a * shorthand version', async () => { + it('rejects backstage: ranges with multiple version parameters', async () => { await expect( backstageResolver.getCandidates( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:*', + 'backstage:^::v=1&v=2', ), + {}, + resolveOptions, ), - ).rejects.toThrow(/invalid backstage version/i); + ).rejects.toThrow(/multiple Backstage versions/i); }); - it('rejects backstage: ranges with an invalid version specified', async () => { - await expect( - backstageResolver.getCandidates( - structUtils.makeDescriptor( - structUtils.makeIdent('backstage', 'core'), - 'backstage:latest', + it.each` + selector + ${'*'} + ${'latest'} + `( + 'rejects backstage: ranges with invalid selector "$selector"', + async ({ selector }) => { + await expect( + backstageResolver.getCandidates( + structUtils.makeDescriptor( + structUtils.makeIdent('backstage', 'core'), + `backstage:${selector}`, + ), + {}, + resolveOptions, ), - ), - ).rejects.toThrow(/invalid backstage version/i); - }); - - it('memoizes manifest retrieval', async () => { - const descriptor1 = structUtils.makeDescriptor( - structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', - ); - - for (let i = 0; i < 5; i++) { - await backstageResolver.getCandidates(descriptor1); - } - - expect(getManifestByVersionMock).toHaveBeenCalledTimes(1); - - const descriptor2 = structUtils.makeDescriptor( - structUtils.makeIdent('backstage', 'core'), - 'backstage:6.78.90', - ); - - for (let i = 0; i < 5; i++) { - await backstageResolver.getCandidates(descriptor2); - } - - expect(getManifestByVersionMock).toHaveBeenCalledTimes(2); - }); + ).rejects.toThrow(/unexpected version selector/i); + }, + ); }); describe('getSatisfying', () => { @@ -219,7 +219,7 @@ describe('BackstageResolver', () => { backstageResolver.getSatisfying( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ), {}, [ @@ -236,6 +236,7 @@ describe('BackstageResolver', () => { 'npm:1.2.3', ), ], + resolveOptions, ), ).resolves.toEqual({ locators: [ @@ -253,7 +254,7 @@ describe('BackstageResolver', () => { backstageResolver.getSatisfying( structUtils.makeDescriptor( structUtils.makeIdent('backstage', 'core'), - 'backstage:1.23.45', + 'backstage:^::v=1.23.45', ), {}, [ @@ -270,6 +271,7 @@ describe('BackstageResolver', () => { 'npm:7.8.9', ), ], + resolveOptions, ), ).resolves.toEqual({ locators: [ @@ -291,8 +293,9 @@ describe('BackstageResolver', () => { ), {}, [], + resolveOptions, ), - ).rejects.toThrow(/unexpected npm: range/i); + ).rejects.toThrow(/unsupported version protocol/i); }); }); }); diff --git a/packages/yarn-plugin/src/resolver/BackstageResolver.ts b/packages/yarn-plugin/src/resolver/BackstageResolver.ts index 7e794f5693..d2d0c98d1e 100644 --- a/packages/yarn-plugin/src/resolver/BackstageResolver.ts +++ b/packages/yarn-plugin/src/resolver/BackstageResolver.ts @@ -20,10 +20,14 @@ import { Locator, Package, Resolver, + ResolveOptions, } from '@yarnpkg/core'; -import semver from 'semver'; import { PROTOCOL } from '../constants'; -import { getCurrentBackstageVersion, getPackageVersion } from '../util'; +import { + bindBackstageVersion, + getCurrentBackstageVersion, + getPackageVersion, +} from '../util'; export class BackstageResolver implements Resolver { static protocol = PROTOCOL; @@ -45,10 +49,7 @@ export class BackstageResolver implements Resolver { */ bindDescriptor(descriptor: Descriptor): Descriptor { if (descriptor.range === 'backstage:^') { - return structUtils.makeDescriptor( - descriptor, - `${PROTOCOL}${getCurrentBackstageVersion()}`, - ); + return bindBackstageVersion(descriptor, getCurrentBackstageVersion()); } return descriptor; @@ -60,28 +61,18 @@ export class BackstageResolver implements Resolver { * concrete version into the appropriate concrete npm version for that * backstage release. */ - async getCandidates(descriptor: Descriptor): Promise { - const range = structUtils.parseRange(descriptor.range); - if (range.protocol !== BackstageResolver.protocol) { - throw new Error( - `Unsupported version protocol in version range "${ - descriptor.range - }" for package ${structUtils.stringifyIdent(descriptor)}`, - ); - } - - if (!semver.valid(range.selector)) { - throw new Error( - `Invalid Backstage version string when resolving version for ${structUtils.stringifyIdent( - descriptor, - )}`, - ); - } - + async getCandidates( + descriptor: Descriptor, + _dependencies: Record, + opts: ResolveOptions, + ): Promise { return [ structUtils.makeLocator( descriptor, - `npm:${await getPackageVersion(descriptor)}`, + `npm:${await getPackageVersion( + descriptor, + opts.project.configuration, + )}`, ), ]; } @@ -96,8 +87,12 @@ export class BackstageResolver implements Resolver { descriptor: Descriptor, _dependencies: Record, locators: Array, + opts: ResolveOptions, ): Promise<{ locators: Locator[]; sorted: boolean }> { - const packageVersion = await getPackageVersion(descriptor); + const packageVersion = await getPackageVersion( + descriptor, + opts.project.configuration, + ); return { locators: locators.filter( diff --git a/packages/yarn-plugin/src/util.ts b/packages/yarn-plugin/src/util.ts index 0b613a477c..ee89a647e3 100644 --- a/packages/yarn-plugin/src/util.ts +++ b/packages/yarn-plugin/src/util.ts @@ -14,18 +14,18 @@ * limitations under the License. */ +import { + Configuration, + Descriptor, + httpUtils, + structUtils, +} from '@yarnpkg/core'; import { ppath, xfs } from '@yarnpkg/fslib'; import { valid as semverValid } from 'semver'; -import { memoize } from 'lodash'; -import { getManifestByVersion as getManifestByVersionBase } from '@backstage/release-manifests'; import { BACKSTAGE_JSON, findPaths } from '@backstage/cli-common'; -import { Descriptor, structUtils } from '@yarnpkg/core'; -import { PROTOCOL } from './constants'; +import { getManifestByVersion } from '@backstage/release-manifests'; -const getManifestByVersion = memoize( - getManifestByVersionBase, - ({ version }) => version, -); +import { PROTOCOL } from './constants'; export const getCurrentBackstageVersion = () => { const workspaceRoot = ppath.resolve(findPaths(ppath.cwd()).targetRoot); @@ -43,20 +43,76 @@ export const getCurrentBackstageVersion = () => { return backstageVersion; }; -export const getPackageVersion = async (descriptor: Descriptor) => { +export const bindBackstageVersion = ( + descriptor: Descriptor, + backstageVersion: string, +) => { + return structUtils.bindDescriptor(descriptor, { v: backstageVersion }); +}; + +export const getPackageVersion = async ( + descriptor: Descriptor, + configuration: Configuration, +) => { const ident = structUtils.stringifyIdent(descriptor); const range = structUtils.parseRange(descriptor.range); if (range.protocol !== PROTOCOL) { - throw new Error(`Unexpected ${range.protocol} range when packing`); + throw new Error( + `Unsupported version protocol in version range "${descriptor.range}" for package ${ident}`, + ); } - if (!semverValid(range.selector)) { - throw new Error(`Missing backstage version in range ${descriptor.range}`); + if (range.selector !== '^') { + throw new Error( + `Unexpected version selector "${range.selector}" for package ${ident}`, + ); + } + + if (!range.params?.v) { + throw new Error( + `Missing Backstage version parameter in range "${descriptor.range}" for package ${ident}`, + ); + } + + if (Array.isArray(range.params.v)) { + throw new Error( + `Multiple Backstage versions specified in range "${descriptor.range}" for package ${ident}`, + ); } const manifest = await getManifestByVersion({ - version: range.selector, + version: range.params.v, + // We override the fetch function used inside getManifestByVersion with a + // custom implementation that calls yarn's built-in `httpUtils` method + // instead. This has a couple of benefits: + // + // 1. This means that the fetch should leverage yarn's built-in cache, so we + // don't need to explicitly memoize the fetch. + // 2. The request should automatically take account of any proxy settings + // configured in yarn. + fetch: async (url: string) => { + const response = await httpUtils.get(url, { + configuration, + jsonResponse: true, + }); + + // The release-manifests package expects fetchFn to resolve with a subset + // of the native HTTP Response object, but yarn's httpUtils implementation + // keeps most of the details hidden. This means we need to construct an + // object which quacks like a Response in the appropriate ways. + return { + // The function has some custom handling for non-200 errors. Yarn + // doesn't provide the status code, but if we've got to this point + // without throwing, we can assume the request has been successful. + status: 200, + // The requested URL, used to correctly report errors + url, + // Yarn automatically parses the response as JSON, so our implementation + // can simply return it. + json: () => response, + }; + }, }); const manifestEntry = manifest.packages.find( diff --git a/plugins/api-docs/CHANGELOG.md b/plugins/api-docs/CHANGELOG.md index 6fb2a3f2cb..bf6ed35b30 100644 --- a/plugins/api-docs/CHANGELOG.md +++ b/plugins/api-docs/CHANGELOG.md @@ -1,5 +1,72 @@ # @backstage/plugin-api-docs +## 0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog@1.26.0-next.2 + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/plugin-catalog@1.25.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## 0.12.2-next.0 + +### Patch Changes + +- 11babd9: Fix link styling in ProvidedApisCard component so it aligns with other card components. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-catalog@1.25.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## 0.12.0 + +### Minor Changes + +- 6836522: Added support for pagination in api-docs plugin - DefaultApiExplorerPage + +### Patch Changes + +- 11f57de: bump `@asyncapi/react-component` to latest `2.x` +- 3cd1dee: Uses theme values to style the API definition schema so that theme overrides apply. +- Updated dependencies + - @backstage/plugin-catalog@1.25.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + ## 0.11.12-next.3 ### Patch Changes diff --git a/plugins/api-docs/package.json b/plugins/api-docs/package.json index 639848a646..b4372097f2 100644 --- a/plugins/api-docs/package.json +++ b/plugins/api-docs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-api-docs", - "version": "0.11.12-next.3", + "version": "0.12.2-next.2", "description": "A Backstage plugin that helps represent API entities in the frontend", "backstage": { "role": "frontend-plugin", diff --git a/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.tsx b/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.tsx index f89f411488..95236aa21a 100644 --- a/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.tsx +++ b/plugins/api-docs/src/components/ApisCards/ProvidedApisCard.tsx @@ -84,12 +84,14 @@ export const ProvidedApisCard = (props: { This {entity.kind.toLocaleLowerCase('en-US')} does not provide any APIs. - - Learn how to change this - + + + Learn how to change this + + } columns={columns} diff --git a/plugins/app-backend/CHANGELOG.md b/plugins/app-backend/CHANGELOG.md index 3a41ded85d..03c8163960 100644 --- a/plugins/app-backend/CHANGELOG.md +++ b/plugins/app-backend/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-app-backend +## 0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-app-node@0.1.28-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.4.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.1 + +## 0.4.3-next.0 + +### Patch Changes + +- 74c3f2a: Fixed a bug where config would not be injected on the `/` and `/index.html` paths. +- d66fa80: Fix root route handling when query parameters are present +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-app-node@0.1.28-next.0 + +## 0.4.0 + +### Minor Changes + +- 815b702: Configuration is no longer injected into static assets if a `index.html.tmpl` file is present. + +### Patch Changes + +- 815b702: The `index.html` templating is now done and served from memory rather than written to the filesystem. This means that you can now use config injection with a read-only filesystem, and you no longer need to use the `app.disableConfigInjection` flag. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-app-node@0.1.27 + ## 0.3.77-next.2 ### Patch Changes diff --git a/plugins/app-backend/package.json b/plugins/app-backend/package.json index b095dedbde..a0faf2154c 100644 --- a/plugins/app-backend/package.json +++ b/plugins/app-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app-backend", - "version": "0.3.77-next.2", + "version": "0.4.3-next.2", "description": "A Backstage backend plugin that serves the Backstage frontend app", "backstage": { "role": "backend-plugin", @@ -83,7 +83,6 @@ "@backstage/cli": "workspace:^", "@backstage/types": "workspace:^", "@types/supertest": "^2.0.8", - "node-fetch": "^2.7.0", "supertest": "^7.0.0" }, "configSchema": "config.d.ts" diff --git a/plugins/app-backend/src/lib/config/injectConfig.ts b/plugins/app-backend/src/lib/config/injectConfig.ts index 9d63d219f4..fddd4ed1b5 100644 --- a/plugins/app-backend/src/lib/config/injectConfig.ts +++ b/plugins/app-backend/src/lib/config/injectConfig.ts @@ -24,13 +24,12 @@ import { InjectOptions } from './types'; */ export async function injectConfig( options: InjectOptions, -): Promise { - // In order to minimize the potential impact when rolling out the new config - // injection, we use both methods for a few releases. This allows the frontend - // app to be behind the backend by a version or two, but temporarily increases - // config injection overhead. - // TODO(Rugvip): After the 1.32 release we can stop calling the static injection if the HTML one is successful - await injectConfigIntoHtml(options); +): Promise<{ injectedPath?: string | undefined; indexHtmlContent?: Buffer }> { + const indexHtmlContent = await injectConfigIntoHtml(options); + if (indexHtmlContent) { + return { indexHtmlContent }; + } - return injectConfigIntoStatic(options); + const injectedPath = await injectConfigIntoStatic(options); + return { injectedPath }; } diff --git a/plugins/app-backend/src/lib/config/injectConfigIntoHtml.test.ts b/plugins/app-backend/src/lib/config/injectConfigIntoHtml.test.ts index 56c916fbb9..c28f5b33a4 100644 --- a/plugins/app-backend/src/lib/config/injectConfigIntoHtml.test.ts +++ b/plugins/app-backend/src/lib/config/injectConfigIntoHtml.test.ts @@ -38,25 +38,22 @@ describe('injectConfigIntoHtml', () => { mockDir.setContent({ 'index.html.tmpl': "<%= config.getNumber('x') %>", }); - await injectConfigIntoHtml({ + const result = await injectConfigIntoHtml({ ...baseOptions, appConfigs: [{ context: 'mock', data: { x: 1 } }], }); - expect(mockDir.content()).toMatchObject({ - 'index.html': '1', - }); + expect(result?.toString('utf8')).toBe('1'); }); it('should inject config', async () => { mockDir.setContent({ 'index.html.tmpl': '', }); - await injectConfigIntoHtml({ + const result = await injectConfigIntoHtml({ ...baseOptions, appConfigs: [{ context: 'mock', data: { x: 1 } }], }); - expect(mockDir.content()).toMatchObject({ - 'index.html': ` + expect(result?.toString('utf8')).toBe(` -`, - }); +`); }); it('should trim script tag endings from injected config', async () => { mockDir.setContent({ 'index.html.tmpl': '', }); - await injectConfigIntoHtml({ + const result = await injectConfigIntoHtml({ ...baseOptions, appConfigs: [ { @@ -84,8 +80,7 @@ describe('injectConfigIntoHtml', () => { }, ], }); - expect(mockDir.content()).toMatchObject({ - 'index.html': ` + expect(result?.toString('utf8')).toBe(` -`, - }); +`); }); }); diff --git a/plugins/app-backend/src/lib/config/injectConfigIntoHtml.ts b/plugins/app-backend/src/lib/config/injectConfigIntoHtml.ts index c0c1ca200a..dbd03e6ab5 100644 --- a/plugins/app-backend/src/lib/config/injectConfigIntoHtml.ts +++ b/plugins/app-backend/src/lib/config/injectConfigIntoHtml.ts @@ -25,13 +25,13 @@ const HTML_TEMPLATE_NAME = 'index.html.tmpl'; /** @internal */ export async function injectConfigIntoHtml( options: InjectOptions, -): Promise { +): Promise { const { rootDir, appConfigs } = options; const templatePath = resolvePath(rootDir, HTML_TEMPLATE_NAME); if (!(await fs.exists(templatePath))) { - return false; + return undefined; } const templateContent = await fs.readFile( @@ -67,13 +67,7 @@ ${JSON.stringify(appConfigs, null, 2) `, ); - await fs.writeFile( - resolvePath(rootDir, 'index.html'), - indexHtmlContentWithConfig, - 'utf8', - ); - - return true; + return Buffer.from(indexHtmlContentWithConfig, 'utf8'); } export function resolvePublicPath(config: Config) { diff --git a/plugins/app-backend/src/service/appPlugin.test.ts b/plugins/app-backend/src/service/appPlugin.test.ts index 1fc4d27cdc..068405c19c 100644 --- a/plugins/app-backend/src/service/appPlugin.test.ts +++ b/plugins/app-backend/src/service/appPlugin.test.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import fetch from 'node-fetch'; import { createMockDirectory, mockServices, @@ -34,7 +33,11 @@ overridePackagePathResolution({ createRootLogger(); describe('appPlugin', () => { - beforeEach(() => { + afterEach(() => { + mockDir.clear(); + }); + + it('boots', async () => { mockDir.setContent({ 'package.json': '{}', dist: { @@ -42,9 +45,7 @@ describe('appPlugin', () => { 'index.html': 'winning', }, }); - }); - it('boots', async () => { const { server } = await startTestBackend({ features: [ appPlugin, @@ -67,4 +68,61 @@ describe('appPlugin', () => { fetch(`http://localhost:${server.port()}`).then(res => res.text()), ).resolves.toBe('winning'); }); + + it('injects config into index.html', async () => { + mockDir.setContent({ + 'package.json': '{}', + dist: { + static: {}, + 'index.html': '', + 'index.html.tmpl': '', + }, + }); + + const { server } = await startTestBackend({ + features: [ + appPlugin, + mockServices.rootConfig.factory({ + data: { + app: { + disableStaticFallbackCache: true, + }, + }, + }), + ], + }); + + const baseUrl = `http://localhost:${server.port()}`; + const withInjectedConfig = ` + +`; + + await expect(fetch(`${baseUrl}`).then(res => res.text())).resolves.toBe( + withInjectedConfig, + ); + + await expect( + fetch(`${baseUrl}?foo=bar`).then(res => res.text()), + ).resolves.toBe(withInjectedConfig); + + await expect( + fetch(`${baseUrl}/index.html`).then(res => res.text()), + ).resolves.toBe(withInjectedConfig); + + await expect( + fetch(`${baseUrl}/index.html?foo=bar`).then(res => res.text()), + ).resolves.toBe(withInjectedConfig); + + await expect( + fetch(`${baseUrl}/api/app/some/html5/route`).then(res => res.text()), + ).resolves.toBe(withInjectedConfig); + + await expect( + fetch(`${baseUrl}/api/app/some/html5/route?foo=bar`).then(res => + res.text(), + ), + ).resolves.toBe(withInjectedConfig); + }); }); diff --git a/plugins/app-backend/src/service/router.ts b/plugins/app-backend/src/service/router.ts index a49a2918c7..24671fe5e9 100644 --- a/plugins/app-backend/src/service/router.ts +++ b/plugins/app-backend/src/service/router.ts @@ -267,7 +267,7 @@ async function createEntryPointRouter({ }) { const staticDir = resolvePath(rootDir, 'static'); - const injectedConfigPath = + const injectResult = appConfigs && (await injectConfig({ appConfigs, logger, rootDir, staticDir })); @@ -278,7 +278,7 @@ async function createEntryPointRouter({ staticRouter.use( express.static(staticDir, { setHeaders: (res, path) => { - if (path === injectedConfigPath) { + if (injectResult?.injectedPath === path) { res.setHeader('Cache-Control', CACHE_CONTROL_REVALIDATE_CACHE); } else { res.setHeader('Cache-Control', CACHE_CONTROL_MAX_CACHE); @@ -302,7 +302,17 @@ async function createEntryPointRouter({ staticRouter.use(notFoundHandler()); router.use('/static', staticRouter); - router.use( + + const rootRouter = Router(); + rootRouter.use((req, _res, next) => { + // Make sure / and /index.html are handled by the HTML5 route below + if (req.path === '/' || req.path === '/index.html') { + next('router'); + } else { + next(); + } + }); + rootRouter.use( express.static(rootDir, { setHeaders: (res, path) => { // The Cache-Control header instructs the browser to not cache html files since it might @@ -315,15 +325,23 @@ async function createEntryPointRouter({ }, }), ); + router.use(rootRouter); + // HTML5 routing router.get('/*', (_req, res) => { - res.sendFile(resolvePath(rootDir, 'index.html'), { - headers: { - // The Cache-Control header instructs the browser to not cache the index.html since it might - // link to static assets from recently deployed versions. - 'cache-control': CACHE_CONTROL_NO_CACHE, - }, - }); + if (injectResult?.indexHtmlContent) { + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.setHeader('Cache-Control', CACHE_CONTROL_NO_CACHE); + res.send(injectResult.indexHtmlContent); + } else { + res.sendFile(resolvePath(rootDir, 'index.html'), { + headers: { + // The Cache-Control header instructs the browser to not cache the index.html since it might + // link to static assets from recently deployed versions. + 'cache-control': CACHE_CONTROL_NO_CACHE, + }, + }); + } }); return router; diff --git a/plugins/app-node/CHANGELOG.md b/plugins/app-node/CHANGELOG.md index b322ce0664..2490d02552 100644 --- a/plugins/app-node/CHANGELOG.md +++ b/plugins/app-node/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-app-node +## 0.1.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/config-loader@1.9.3-next.1 + +## 0.1.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.1.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config-loader@1.9.2 + +## 0.1.27 + +### Patch Changes + +- Updated dependencies + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + ## 0.1.27-next.2 ### Patch Changes diff --git a/plugins/app-node/package.json b/plugins/app-node/package.json index ca7f825f5f..1abd101c09 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.27-next.2", + "version": "0.1.28-next.2", "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 f0246e59f5..73487d2f2d 100644 --- a/plugins/app-visualizer/CHANGELOG.md +++ b/plugins/app-visualizer/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-app-visualizer +## 0.1.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + +## 0.1.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## 0.1.12 + +### Patch Changes + +- e586e77: New `devDependency` for local development setup. +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + ## 0.1.12-next.3 ### Patch Changes diff --git a/plugins/app-visualizer/package.json b/plugins/app-visualizer/package.json index 042ff47c7e..fd2297bd2f 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.12-next.3", + "version": "0.1.14-next.2", "description": "Visualizes the Backstage app structure", "backstage": { "role": "frontend-plugin", diff --git a/plugins/app/CHANGELOG.md b/plugins/app/CHANGELOG.md index de89feadae..b7a68b9fe1 100644 --- a/plugins/app/CHANGELOG.md +++ b/plugins/app/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-app +## 0.1.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 0.1.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## 0.1.4-next.0 + +### Patch Changes + +- e5fa018: The OAuth 2 client implementations will now attempt to refresh the session when the existing session doesn't have the required scopes. The previous behavior was to only try to refresh the session of it was missing, and otherwise directly request a new session. This fixes an issue where some auth providers will not return access tokens with certain scopes unless explicitly requested, leading to an auth popup even if the underlying session already had been granted the requested scopes. +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-permission-react@0.4.28 + +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-permission-react@0.4.28 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/app/package.json b/plugins/app/package.json index 28d3495161..a67314e518 100644 --- a/plugins/app/package.json +++ b/plugins/app/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-app", - "version": "0.1.2-next.2", + "version": "0.1.4-next.2", "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 f8d02959dc..3990ad28bc 100644 --- a/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-atlassian-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-atlassian-provider +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-atlassian-provider/package.json b/plugins/auth-backend-module-atlassian-provider/package.json index e02c1740b6..42f9da9113 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.3.2-next.2", + "version": "0.3.3-next.2", "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 c62fe61b67..884a10bdf9 100644 --- a/plugins/auth-backend-module-auth0-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-auth0-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-auth0-provider +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 3cfa733c5b..43f5d6cfd1 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.1.2-next.2", + "version": "0.1.3-next.2", "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 e4b35d4672..ed6fca9fb3 100644 --- a/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-aws-alb-provider/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-auth-backend-module-aws-alb-provider +## 0.3.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.3.1-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + +## 0.3.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-auth-backend@0.24.1-next.0 + +## 0.3.0 + +### Minor Changes + +- 75168e3: **BREAKING**: The AWS ALB `fullProfile` will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result. + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.3.0-next.2 ### 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 dd579f13dc..4f513dc904 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.3.0-next.2", + "version": "0.3.1-next.2", "description": "The aws-alb provider module for the Backstage auth backend.", "backstage": { "role": "backend-plugin-module", @@ -42,8 +42,7 @@ "@backstage/plugin-auth-backend": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "jose": "^5.0.0", - "node-cache": "^5.1.2", - "node-fetch": "^2.7.0" + "node-cache": "^5.1.2" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/plugins/auth-backend-module-aws-alb-provider/src/helpers.ts b/plugins/auth-backend-module-aws-alb-provider/src/helpers.ts index 24026e2c9c..5d06de60a0 100644 --- a/plugins/auth-backend-module-aws-alb-provider/src/helpers.ts +++ b/plugins/auth-backend-module-aws-alb-provider/src/helpers.ts @@ -13,11 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { KeyObject } from 'crypto'; import * as crypto from 'crypto'; import { JWTHeaderParameters, decodeJwt } from 'jose'; import NodeCache from 'node-cache'; -import fetch from 'node-fetch'; import { PassportProfile, ProfileInfo } from '@backstage/plugin-auth-node'; import { AuthenticationError } from '@backstage/errors'; diff --git a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md index 7f925c8318..cdc6c21097 100644 --- a/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-azure-easyauth-provider/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-auth-backend-module-azure-easyauth-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.2.2-next.2 ### 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 81bbf78daa..159ced3d65 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.2-next.2", + "version": "0.2.3-next.2", "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 8c4ca68dc0..9742024bea 100644 --- a/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-bitbucket-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-bitbucket-provider/package.json b/plugins/auth-backend-module-bitbucket-provider/package.json index 96fcd14a60..8134785461 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.2.2-next.2", + "version": "0.2.3-next.2", "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 f3c14ca776..b494d0f98b 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-bitbucket-server-provider/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-auth-backend-module-bitbucket-server-provider +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.1.2-next.2 ### 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 4ff6a60c3d..306c931bda 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.1.2-next.2", + "version": "0.1.3-next.2", "description": "The bitbucket-server-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", @@ -36,7 +36,6 @@ "dependencies": { "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", - "node-fetch": "^2.7.0", "passport": "^0.7.0", "passport-oauth2": "^1.6.1" }, diff --git a/plugins/auth-backend-module-bitbucket-server-provider/src/helpers.ts b/plugins/auth-backend-module-bitbucket-server-provider/src/helpers.ts index fc16253b27..26b45d1f6d 100644 --- a/plugins/auth-backend-module-bitbucket-server-provider/src/helpers.ts +++ b/plugins/auth-backend-module-bitbucket-server-provider/src/helpers.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import fetch from 'node-fetch'; import { PassportProfile } from '@backstage/plugin-auth-node'; export async function fetchProfile(options: { diff --git a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md index 99c6e6a9bf..05bb865a9c 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-cloudflare-access-provider/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-auth-backend-module-cloudflare-access-provider +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.3.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.3.2 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts index 72dc599cea..b73c8d87a5 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/config.d.ts @@ -42,7 +42,7 @@ export interface Config { /** * The backstage token expiration. */ - backstageTokenExpiration?: HumanDuration; + backstageTokenExpiration?: HumanDuration | string; }; }; } diff --git a/plugins/auth-backend-module-cloudflare-access-provider/package.json b/plugins/auth-backend-module-cloudflare-access-provider/package.json index 1e3c415cb8..a6ab768f0f 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.3.2-next.2", + "version": "0.3.3-next.2", "description": "The cloudflare-access-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", @@ -39,8 +39,7 @@ "@backstage/errors": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", - "jose": "^5.0.0", - "node-fetch": "^2.7.0" + "jose": "^5.0.0" }, "devDependencies": { "@backstage/backend-defaults": "workspace:^", diff --git a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.ts b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.ts index 3077258dd6..64f79f113a 100644 --- a/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.ts +++ b/plugins/auth-backend-module-cloudflare-access-provider/src/helpers.ts @@ -23,7 +23,6 @@ import { } from '@backstage/errors'; import express from 'express'; import { createRemoteJWKSet, jwtVerify } from 'jose'; -import fetch, { Headers } from 'node-fetch'; import { CACHE_PREFIX, CF_JWT_HEADER, @@ -87,8 +86,7 @@ export class AuthHelper { // Only throw if both are not provided by Cloudflare Access since either // can be used. throw new AuthenticationError( - `Missing ${this.jwtHeaderName} and - ${this.authorizationCookieName} from Cloudflare Access`, + `Missing ${this.jwtHeaderName} and ${this.authorizationCookieName} from Cloudflare Access`, ); } diff --git a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md index 3a4afd76b5..312a18eac7 100644 --- a/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gcp-iap-provider/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-auth-backend-module-gcp-iap-provider +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/types@1.2.0 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.3.2-next.2 ### 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 6ecd2d3b01..f39dde45b9 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.3.2-next.2", + "version": "0.3.3-next.2", "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 30ead105c7..1b59b8647f 100644 --- a/plugins/auth-backend-module-github-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-github-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-github-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-github-provider/package.json b/plugins/auth-backend-module-github-provider/package.json index 461571084b..49dca01723 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.2.2-next.2", + "version": "0.2.3-next.2", "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 597a5f9862..ecfa128461 100644 --- a/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-gitlab-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-gitlab-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-gitlab-provider/package.json b/plugins/auth-backend-module-gitlab-provider/package.json index c4c1a50ee1..b006aeb15f 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.2.2-next.2", + "version": "0.2.3-next.2", "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 70752df8dd..439de2acdc 100644 --- a/plugins/auth-backend-module-google-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-google-provider/CHANGELOG.md @@ -1,5 +1,39 @@ # @backstage/plugin-auth-backend-module-google-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- 79b055a: Pass through `includeGrantedScopes` in order to persist scopes across refresh calls +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- b833660: Fix visibility of config for use in front end code +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-google-provider/package.json b/plugins/auth-backend-module-google-provider/package.json index 9dc8c6efdd..e336c96987 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.2.2-next.2", + "version": "0.2.3-next.2", "description": "A Google auth provider module for the Backstage auth backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-google-provider/src/authenticator.ts b/plugins/auth-backend-module-google-provider/src/authenticator.ts index 9f1e298ae8..b0c58b777b 100644 --- a/plugins/auth-backend-module-google-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-google-provider/src/authenticator.ts @@ -73,6 +73,7 @@ export const googleAuthenticator = createOAuthAuthenticator({ return helper.start(input, { accessType: 'offline', prompt: 'consent', + includeGrantedScopes: 'true', }); }, diff --git a/plugins/auth-backend-module-google-provider/src/module.test.ts b/plugins/auth-backend-module-google-provider/src/module.test.ts index 8ece0c1942..608428d9f5 100644 --- a/plugins/auth-backend-module-google-provider/src/module.test.ts +++ b/plugins/auth-backend-module-google-provider/src/module.test.ts @@ -67,6 +67,7 @@ describe('authModuleGoogleProvider', () => { prompt: 'consent', response_type: 'code', client_id: 'my-client-id', + include_granted_scopes: 'true', redirect_uri: `http://localhost:${server.port()}/api/auth/google/handler/frame`, state: expect.any(String), scope: diff --git a/plugins/auth-backend-module-guest-provider/CHANGELOG.md b/plugins/auth-backend-module-guest-provider/CHANGELOG.md index e8ebf5eeb9..8c03d41a0b 100644 --- a/plugins/auth-backend-module-guest-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-guest-provider/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-auth-backend-module-guest-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-guest-provider/package.json b/plugins/auth-backend-module-guest-provider/package.json index 7c73f7eac5..22b24139f6 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.2-next.2", + "version": "0.2.3-next.2", "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 5a88594cb7..c9ceff5f82 100644 --- a/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-microsoft-provider/CHANGELOG.md @@ -1,5 +1,38 @@ # @backstage/plugin-auth-backend-module-microsoft-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-microsoft-provider/package.json b/plugins/auth-backend-module-microsoft-provider/package.json index be830895cc..4853cf95a2 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.2.2-next.2", + "version": "0.2.3-next.2", "description": "The microsoft-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", @@ -38,7 +38,6 @@ "@backstage/plugin-auth-node": "workspace:^", "express": "^4.18.2", "jose": "^5.0.0", - "node-fetch": "^2.7.0", "passport-microsoft": "^1.0.0" }, "devDependencies": { diff --git a/plugins/auth-backend-module-microsoft-provider/src/strategy.ts b/plugins/auth-backend-module-microsoft-provider/src/strategy.ts index 910bd85d1d..3a89b19c87 100644 --- a/plugins/auth-backend-module-microsoft-provider/src/strategy.ts +++ b/plugins/auth-backend-module-microsoft-provider/src/strategy.ts @@ -16,7 +16,6 @@ import { PassportProfile } from '@backstage/plugin-auth-node'; import { decodeJwt } from 'jose'; -import fetch from 'node-fetch'; import { Strategy as MicrosoftStrategy } from 'passport-microsoft'; export class ExtendedMicrosoftStrategy extends MicrosoftStrategy { @@ -103,9 +102,9 @@ export class ExtendedMicrosoftStrategy extends MicrosoftStrategy { }, }, ); - const data = await res.buffer(); + const data = await res.arrayBuffer(); - return `data:image/jpeg;base64,${data.toString('base64')}`; + return `data:image/jpeg;base64,${Buffer.from(data).toString('base64')}`; } catch (error) { return undefined; } diff --git a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md index 423e01124b..2d1a8ffd95 100644 --- a/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-oauth2-provider +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oauth2-provider/package.json b/plugins/auth-backend-module-oauth2-provider/package.json index 2bbbe4bb67..fb0ee690df 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.3.2-next.2", + "version": "0.3.3-next.2", "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 3956310123..ef29374df0 100644 --- a/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oauth2-proxy-provider/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-auth-backend-module-oauth2-proxy-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.2.2-next.2 ### 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 ea0b9c9481..84258c01c7 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.2-next.2", + "version": "0.2.3-next.2", "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 806529ba7f..1f4f574d06 100644 --- a/plugins/auth-backend-module-oidc-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-oidc-provider/CHANGELOG.md @@ -1,5 +1,42 @@ # @backstage/plugin-auth-backend-module-oidc-provider +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-backend@0.24.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.1-next.1 + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-auth-backend@0.24.1-next.0 + +## 0.3.2 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/plugin-auth-backend@0.24.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-oidc-provider/package.json b/plugins/auth-backend-module-oidc-provider/package.json index 7a51a1115d..9e10260bbd 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.3.2-next.2", + "version": "0.3.3-next.2", "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 10837b65b5..36c5a56db6 100644 --- a/plugins/auth-backend-module-okta-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-okta-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-okta-provider +## 0.1.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.1.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.1.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.1.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.1.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-okta-provider/package.json b/plugins/auth-backend-module-okta-provider/package.json index 247cc1601f..8ca4e26db2 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.1.2-next.2", + "version": "0.1.3-next.2", "description": "The okta-provider backend module for the auth plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md index 46d4a272e3..be3263db85 100644 --- a/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-onelogin-provider/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-auth-backend-module-onelogin-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-onelogin-provider/package.json b/plugins/auth-backend-module-onelogin-provider/package.json index f3bfcc5547..4f92065d30 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.2.2-next.2", + "version": "0.2.3-next.2", "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 8ace47b0d6..f1e14601f9 100644 --- a/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-pinniped-provider/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-auth-backend-module-pinniped-provider +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.2-next.2 ### Patch Changes diff --git a/plugins/auth-backend-module-pinniped-provider/package.json b/plugins/auth-backend-module-pinniped-provider/package.json index d745576615..a70e51018d 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.2.2-next.2", + "version": "0.2.3-next.2", "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 64684b8b19..088d9acef5 100644 --- a/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md +++ b/plugins/auth-backend-module-vmware-cloud-provider/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-auth-backend-module-vmware-cloud-provider +## 0.4.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/catalog-model@1.7.2-next.0 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + +## 0.4.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + ## 0.4.1-next.2 ### 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 a54a7c4ed4..a005fd1762 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.4.1-next.2", + "version": "0.4.2-next.2", "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 c2eca8003a..b41eee890e 100644 --- a/plugins/auth-backend/CHANGELOG.md +++ b/plugins/auth-backend/CHANGELOG.md @@ -1,5 +1,138 @@ # @backstage/plugin-auth-backend +## 0.24.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.2 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.2 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.2 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.24.1-next.1 + +### Patch Changes + +- c907440: Improved error forwarding for OAuth refresh endpoints +- 40518ab: Fix issue with `jwks` endpoint returning invalid data with `firestore` +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.1 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.1 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.1 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.1 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.24.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.1-next.0 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-github-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-google-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.3-next.0 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.3-next.0 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.3-next.0 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.24.0 + +### Minor Changes + +- 75168e3: **BREAKING**: The AWS ALB `fullProfile` will no longer have the its username or email converted to lowercase. This is to ensure unique handling of the users. You may need to update and configure a custom sign-in resolver or profile transform as a result. + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-auth-backend-module-google-provider@0.2.2 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-backend-module-aws-alb-provider@0.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/plugin-auth-backend-module-cloudflare-access-provider@0.3.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-auth-backend-module-oidc-provider@0.3.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-auth-backend-module-atlassian-provider@0.3.2 + - @backstage/plugin-auth-backend-module-auth0-provider@0.1.2 + - @backstage/plugin-auth-backend-module-azure-easyauth-provider@0.2.2 + - @backstage/plugin-auth-backend-module-bitbucket-provider@0.2.2 + - @backstage/plugin-auth-backend-module-bitbucket-server-provider@0.1.2 + - @backstage/plugin-auth-backend-module-gcp-iap-provider@0.3.2 + - @backstage/plugin-auth-backend-module-github-provider@0.2.2 + - @backstage/plugin-auth-backend-module-gitlab-provider@0.2.2 + - @backstage/plugin-auth-backend-module-microsoft-provider@0.2.2 + - @backstage/plugin-auth-backend-module-oauth2-provider@0.3.2 + - @backstage/plugin-auth-backend-module-oauth2-proxy-provider@0.2.2 + - @backstage/plugin-auth-backend-module-okta-provider@0.1.2 + - @backstage/plugin-auth-backend-module-onelogin-provider@0.2.2 + ## 0.24.0-next.2 ### Patch Changes diff --git a/plugins/auth-backend/config.d.ts b/plugins/auth-backend/config.d.ts index a7ea18ed1d..d2725e99a5 100644 --- a/plugins/auth-backend/config.d.ts +++ b/plugins/auth-backend/config.d.ts @@ -143,7 +143,7 @@ export interface Config { /** * The backstage token expiration. */ - backstageTokenExpiration?: HumanDuration; + backstageTokenExpiration?: HumanDuration | string; }; /** * Additional app origins to allow for authenticating diff --git a/plugins/auth-backend/package.json b/plugins/auth-backend/package.json index 22c78f94b4..63fa6861d5 100644 --- a/plugins/auth-backend/package.json +++ b/plugins/auth-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-backend", - "version": "0.24.0-next.2", + "version": "0.24.1-next.2", "description": "A Backstage backend plugin that handles authentication", "backstage": { "role": "backend-plugin", @@ -89,7 +89,6 @@ "minimatch": "^9.0.0", "morgan": "^1.10.0", "node-cache": "^5.1.2", - "node-fetch": "^2.7.0", "openid-client": "^5.2.1", "passport": "^0.7.0", "passport-auth0": "^1.4.3", diff --git a/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts b/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts index b04cf8a6b3..8e30dcc6f8 100644 --- a/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts +++ b/plugins/auth-backend/src/identity/FirestoreKeyStore.test.ts @@ -24,7 +24,9 @@ import { } from './FirestoreKeyStore'; import { AnyJWK } from './types'; -const data = jest.fn().mockReturnValue('data'); +const data = jest + .fn() + .mockReturnValue({ key: { kid: 'something' }, kid: 'something' }); const toDate = jest.fn().mockReturnValue('date'); const get = jest.fn().mockReturnValue({ docs: [{ data, createTime: { toDate } }], @@ -145,7 +147,7 @@ describe('FirestoreKeyStore', () => { expect(firestoreMock.doc).toHaveBeenCalledWith(key.kid); expect(firestoreMock.set).toHaveBeenCalledWith({ kid: key.kid, - key: JSON.stringify(key), + key, }); }); @@ -180,7 +182,26 @@ describe('FirestoreKeyStore', () => { expect(data).toHaveBeenCalledTimes(1); expect(toDate).toHaveBeenCalledTimes(1); expect(items).toMatchObject({ - items: [{ key: 'data', createdAt: 'date' }], + items: [{ key: { kid: 'something' }, createdAt: 'date' }], + }); + }); + + it('supports older string versions of the keys', async () => { + data.mockReturnValue({ + key: JSON.stringify({ kid: 'something' }), + kid: 'something', + }); + + const keyStore = await FirestoreKeyStore.create(firestoreSettings); + const items = await keyStore.listKeys(); + + expect(setTimeout).toHaveBeenCalledTimes(1); + expect(firestoreMock.collection).toHaveBeenCalledWith(path); + expect(firestoreMock.get).toHaveBeenCalledTimes(1); + expect(data).toHaveBeenCalledTimes(1); + expect(toDate).toHaveBeenCalledTimes(1); + expect(items).toMatchObject({ + items: [{ key: { kid: 'something' }, createdAt: 'date' }], }); }); }); diff --git a/plugins/auth-backend/src/identity/FirestoreKeyStore.ts b/plugins/auth-backend/src/identity/FirestoreKeyStore.ts index b5f4f5dcfb..3b998a4fe9 100644 --- a/plugins/auth-backend/src/identity/FirestoreKeyStore.ts +++ b/plugins/auth-backend/src/identity/FirestoreKeyStore.ts @@ -75,13 +75,10 @@ export class FirestoreKeyStore implements KeyStore { async addKey(key: AnyJWK): Promise { await this.withTimeout( - this.database - .collection(this.path) - .doc(key.kid) - .set({ - kid: key.kid, - key: JSON.stringify(key), - }), + this.database.collection(this.path).doc(key.kid).set({ + kid: key.kid, + key: key, + }), ); } @@ -91,10 +88,14 @@ export class FirestoreKeyStore implements KeyStore { ); return { - items: keys.docs.map(key => ({ - key: key.data() as AnyJWK, - createdAt: key.createTime.toDate(), - })), + items: keys.docs.map(doc => { + const { key } = doc.data(); + + return { + createdAt: doc.createTime.toDate(), + key: typeof key === 'string' ? JSON.parse(key) : key, + }; + }), }; } diff --git a/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.test.ts b/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.test.ts index 4d94634473..d9e80263ee 100644 --- a/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.test.ts +++ b/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.test.ts @@ -272,28 +272,63 @@ describe('PassportStrategyHelper', () => { ); }); - it('should reject with an error if refresh failed', async () => { - class MyCustomOAuth2Error { - getOAuthAccessToken( - _refreshToken: string, - _options: any, - callback: Function, - ) { - callback(new Error('Unknown error')); - } - } + it('should forward simple errors', async () => { class MyCustomRefreshTokenSuccess extends passport.Strategy { - _oauth2 = new MyCustomOAuth2Error(); + _oauth2 = new (class { + getOAuthAccessToken(_r: string, _o: any, cb: Function) { + cb(new Error('Unknown error')); + } + })(); } - const mockStrategy = new MyCustomRefreshTokenSuccess(); - const refreshTokenPromise = executeRefreshTokenStrategy( - mockStrategy, - 'REFRESH_TOKEN', - 'a', + await expect( + executeRefreshTokenStrategy( + new MyCustomRefreshTokenSuccess(), + 'REFRESH_TOKEN', + 'a', + ), + ).rejects.toThrow( + 'Failed to refresh access token; caused by Error: Unknown error', ); - await expect(refreshTokenPromise).rejects.toThrow( - 'Failed to refresh access token Error: Unknown error', + }); + + it('should forward string errors', async () => { + class MyCustomRefreshTokenSuccess extends passport.Strategy { + _oauth2 = new (class { + getOAuthAccessToken(_r: string, _o: any, cb: Function) { + cb('some silly string error'); + } + })(); + } + + await expect( + executeRefreshTokenStrategy( + new MyCustomRefreshTokenSuccess(), + 'REFRESH_TOKEN', + 'a', + ), + ).rejects.toThrow( + "Failed to refresh access token; caused by unknown error 'some silly string error'", + ); + }); + + it('should forward object errors', async () => { + class MyCustomRefreshTokenSuccess extends passport.Strategy { + _oauth2 = new (class { + getOAuthAccessToken(_r: string, _o: any, cb: Function) { + cb({ name: 'SomeError', message: 'some message' }); + } + })(); + } + + await expect( + executeRefreshTokenStrategy( + new MyCustomRefreshTokenSuccess(), + 'REFRESH_TOKEN', + 'a', + ), + ).rejects.toThrow( + 'Failed to refresh access token; caused by SomeError: some message', ); }); diff --git a/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.ts b/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.ts index 88d3dbfa04..ef9284c1fb 100644 --- a/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.ts +++ b/plugins/auth-backend/src/lib/passport/PassportStrategyHelper.ts @@ -21,6 +21,7 @@ import { InternalOAuthError } from 'passport-oauth2'; import { ProfileInfo } from '@backstage/plugin-auth-node'; import { PassportProfile } from './types'; import { OAuthStartResponse } from '../../providers/types'; +import { ForwardedError } from '@backstage/errors'; export type PassportDoneCallback = ( err?: Error, @@ -66,7 +67,10 @@ export const makeProfileInfo = ( displayName = decoded.name; } } catch (e) { - throw new Error(`Failed to parse id token and get profile info, ${e}`); + throw new ForwardedError( + `Failed to parse id token and get profile info`, + e, + ); } } @@ -176,7 +180,7 @@ export const executeRefreshTokenStrategy = async ( params: any, ) => { if (err) { - reject(new Error(`Failed to refresh access token ${err.toString()}`)); + reject(new ForwardedError(`Failed to refresh access token`, err)); } if (!accessToken) { reject( diff --git a/plugins/auth-node/CHANGELOG.md b/plugins/auth-node/CHANGELOG.md index 2a23784592..e3209aaa45 100644 --- a/plugins/auth-node/CHANGELOG.md +++ b/plugins/auth-node/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-auth-node +## 0.5.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.5.5-next.1 + +### Patch Changes + +- c907440: Improved error forwarding for OAuth refresh endpoints +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.5.5-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.5.4 + +### Patch Changes + +- a0a9a4a: Browsers silently drop cookies that exceed 4KB, which can be problematic for refresh tokens and other large cookies.This update ensures that large cookies, like refresh tokens, are not dropped by browsers, maintaining the integrity of the authentication process. The changes include both the implementation of the cookie splitting logic and corresponding tests to validate the new functionality. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.5.4-next.2 ### Patch Changes diff --git a/plugins/auth-node/package.json b/plugins/auth-node/package.json index cc81d88b27..cb7f02fd95 100644 --- a/plugins/auth-node/package.json +++ b/plugins/auth-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-auth-node", - "version": "0.5.4-next.2", + "version": "0.5.5-next.2", "backstage": { "role": "node-library", "pluginId": "auth", @@ -44,12 +44,11 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/types": "workspace:^", - "@types/express": "*", + "@types/express": "^4.17.6", "@types/passport": "^1.0.3", "express": "^4.17.1", "jose": "^5.0.0", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "passport": "^0.7.0", "winston": "^3.2.1", "zod": "^3.22.4", diff --git a/plugins/auth-node/src/passport/PassportHelpers.ts b/plugins/auth-node/src/passport/PassportHelpers.ts index d1ddee20a7..9c9198fbf1 100644 --- a/plugins/auth-node/src/passport/PassportHelpers.ts +++ b/plugins/auth-node/src/passport/PassportHelpers.ts @@ -19,6 +19,7 @@ import { decodeJwt } from 'jose'; import { Strategy } from 'passport'; import { PassportProfile } from './types'; import { ProfileInfo } from '../types'; +import { ForwardedError } from '@backstage/errors'; // Re-declared here to avoid direct dependency on passport-oauth2 /** @internal */ @@ -76,7 +77,10 @@ export class PassportHelpers { displayName = decoded.name; } } catch (e) { - throw new Error(`Failed to parse id token and get profile info, ${e}`); + throw new ForwardedError( + `Failed to parse id token and get profile info`, + e, + ); } } @@ -191,9 +195,7 @@ export class PassportHelpers { params: any, ) => { if (err) { - reject( - new Error(`Failed to refresh access token ${err.toString()}`), - ); + reject(new ForwardedError(`Failed to refresh access token`, err)); } if (!accessToken) { reject( diff --git a/plugins/auth-react/CHANGELOG.md b/plugins/auth-react/CHANGELOG.md index 723d2b157d..8f47451e59 100644 --- a/plugins/auth-react/CHANGELOG.md +++ b/plugins/auth-react/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-auth-react +## 0.1.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## 0.1.10-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## 0.1.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## 0.1.8 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + ## 0.1.8-next.2 ### Patch Changes diff --git a/plugins/auth-react/package.json b/plugins/auth-react/package.json index 2e44e63963..5241176b4c 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.8-next.2", + "version": "0.1.10-next.2", "description": "Web library for the auth plugin", "backstage": { "role": "web-library", diff --git a/plugins/bitbucket-cloud-common/CHANGELOG.md b/plugins/bitbucket-cloud-common/CHANGELOG.md index 96ce72a61b..c0d50270cf 100644 --- a/plugins/bitbucket-cloud-common/CHANGELOG.md +++ b/plugins/bitbucket-cloud-common/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-bitbucket-cloud-common +## 0.2.26-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.1 + +## 0.2.26-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + +## 0.2.25 + +### Patch Changes + +- 23f1da2: Updated dependency `ts-morph` to `^24.0.0`. +- Updated dependencies + - @backstage/integration@1.15.2 + ## 0.2.25-next.0 ### Patch Changes diff --git a/plugins/bitbucket-cloud-common/bitbucket-cloud.oas.json b/plugins/bitbucket-cloud-common/bitbucket-cloud.oas.json index d897d83047..ead80230c6 100644 --- a/plugins/bitbucket-cloud-common/bitbucket-cloud.oas.json +++ b/plugins/bitbucket-cloud-common/bitbucket-cloud.oas.json @@ -24400,7 +24400,7 @@ "title": "Pagination", "description": "Learn more about pagination", "icon": "data:image/svg+xml;base64,b'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMjM4LjgyIDE1MS42Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2IyZDRmZjt9LmNscy0ye2ZpbGw6IzRjOWFmZjt9LmNscy0ze2ZpbGw6IzAwNTJjYzt9LmNscy00e29wYWNpdHk6MC42O30uY2xzLTV7ZmlsbDp1cmwoI2xpbmVhci1ncmFkaWVudCk7fS5jbHMtNntmaWxsOnVybCgjbGluZWFyLWdyYWRpZW50LTIpO30uY2xzLTd7ZmlsbDp1cmwoI2xpbmVhci1ncmFkaWVudC0zKTt9LmNscy04e2ZpbGw6dXJsKCNsaW5lYXItZ3JhZGllbnQtNCk7fS5jbHMtOXtmaWxsOnVybCgjbGluZWFyLWdyYWRpZW50LTUpO30uY2xzLTEwLC5jbHMtMTEsLmNscy0xMntmaWxsOm5vbmU7fS5jbHMtMTB7c3Ryb2tlOiMzMzg0ZmY7fS5jbHMtMTAsLmNscy0xMSwuY2xzLTEyLC5jbHMtMTN7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLXdpZHRoOjJweDt9LmNscy0xMXtzdHJva2U6I2ZmYWIwMDt9LmNscy0xMntzdHJva2U6I2ZhZmJmYzt9LmNscy0xM3tmaWxsOiNmZmFiMDA7c3Ryb2tlOiMyNjg0ZmY7fTwvc3R5bGU+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHkxPSI2NS4xNyIgeDI9Ijg2LjM4IiB5Mj0iNjUuMTciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiM0YzlhZmYiLz48c3RvcCBvZmZzZXQ9IjAuMDgiIHN0b3AtY29sb3I9IiM0YzlhZmYiIHN0b3Atb3BhY2l0eT0iMC45NCIvPjxzdG9wIG9mZnNldD0iMC4yNCIgc3RvcC1jb2xvcj0iIzRjOWFmZiIgc3RvcC1vcGFjaXR5PSIwLjc4Ii8+PHN0b3Agb2Zmc2V0PSIwLjQ1IiBzdG9wLWNvbG9yPSIjNGM5YWZmIiBzdG9wLW9wYWNpdHk9IjAuNTMiLz48c3RvcCBvZmZzZXQ9IjAuNTUiIHN0b3AtY29sb3I9IiM0YzlhZmYiIHN0b3Atb3BhY2l0eT0iMC40Ii8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC0yIiB4MT0iMTUyLjQ0IiB5MT0iNjUuMTciIHgyPSIyMzguODIiIHkyPSI2NS4xNyIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudCIvPjxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTMiIHgxPSIxOC44NSIgeTE9IjExOC43OCIgeDI9IjEyNi4wOCIgeTI9IjExLjU2IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+PHN0b3Agb2Zmc2V0PSIwLjA2IiBzdG9wLWNvbG9yPSIjMDA2NWZmIi8+PHN0b3Agb2Zmc2V0PSIwLjE5IiBzdG9wLWNvbG9yPSIjMDA2NWZmIiBzdG9wLW9wYWNpdHk9IjAuOTQiLz48c3RvcCBvZmZzZXQ9IjAuNDYiIHN0b3AtY29sb3I9IiMwMDY1ZmYiIHN0b3Atb3BhY2l0eT0iMC43OCIvPjxzdG9wIG9mZnNldD0iMC44MiIgc3RvcC1jb2xvcj0iIzAwNjVmZiIgc3RvcC1vcGFjaXR5PSIwLjUzIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDA2NWZmIiBzdG9wLW9wYWNpdHk9IjAuNCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNCIgeDE9IjExMi43NSIgeTE9IjExOC43OCIgeDI9IjIxOS45NyIgeTI9IjExLjU2IiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50LTMiLz48bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC01IiB4MT0iNTAuOTciIHkxPSIxMzMuNjEiIHgyPSIxODcuODYiIHkyPSItMy4yOCIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiPjxzdG9wIG9mZnNldD0iMC42NiIgc3RvcC1jb2xvcj0iIzI1Mzg1OCIvPjxzdG9wIG9mZnNldD0iMC44OCIgc3RvcC1jb2xvcj0iIzI1Mzg1OCIgc3RvcC1vcGFjaXR5PSIwLjgzIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMjUzODU4IiBzdG9wLW9wYWNpdHk9IjAuNyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjx0aXRsZT5WaWV3IFZlcnNpb25zPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iU29mdHdhcmUiPjxjaXJjbGUgY2xhc3M9ImNscy0xIiBjeD0iOTQuNTMiIGN5PSIxNDcuOTMiIHI9IjMuNjciLz48Y2lyY2xlIGNsYXNzPSJjbHMtMiIgY3g9IjEwNi45NCIgY3k9IjE0Ny45MyIgcj0iMy42NyIvPjxjaXJjbGUgY2xhc3M9ImNscy0zIiBjeD0iMTE5LjM0IiBjeT0iMTQ3LjkzIiByPSIzLjY3Ii8+PGNpcmNsZSBjbGFzcz0iY2xzLTIiIGN4PSIxMzEuNzUiIGN5PSIxNDcuOTMiIHI9IjMuNjciLz48Y2lyY2xlIGNsYXNzPSJjbHMtMSIgY3g9IjE0NC4xNiIgY3k9IjE0Ny45MyIgcj0iMy42NyIvPjxnIGNsYXNzPSJjbHMtNCI+PHJlY3QgaWQ9Il9SZWN0YW5nbGVfIiBkYXRhLW5hbWU9IiZsdDtSZWN0YW5nbGUmZ3Q7IiBjbGFzcz0iY2xzLTUiIHk9IjI1LjkyIiB3aWR0aD0iODYuMzgiIGhlaWdodD0iNzguNDkiLz48L2c+PGcgY2xhc3M9ImNscy00Ij48cmVjdCBpZD0iX1JlY3RhbmdsZV8yIiBkYXRhLW5hbWU9IiZsdDtSZWN0YW5nbGUmZ3Q7IiBjbGFzcz0iY2xzLTYiIHg9IjE1Mi40NCIgeT0iMjUuOTIiIHdpZHRoPSI4Ni4zOCIgaGVpZ2h0PSI3OC40OSIvPjwvZz48cmVjdCBpZD0iX1JlY3RhbmdsZV8zIiBkYXRhLW5hbWU9IiZsdDtSZWN0YW5nbGUmZ3Q7IiBjbGFzcz0iY2xzLTciIHg9IjE2LjI4IiB5PSIxNC4xMiIgd2lkdGg9IjExMi4zNiIgaGVpZ2h0PSIxMDIuMDkiLz48cmVjdCBpZD0iX1JlY3RhbmdsZV80IiBkYXRhLW5hbWU9IiZsdDtSZWN0YW5nbGUmZ3Q7IiBjbGFzcz0iY2xzLTgiIHg9IjExMC4xOCIgeT0iMTQuMTIiIHdpZHRoPSIxMTIuMzYiIGhlaWdodD0iMTAyLjA5Ii8+PHJlY3QgaWQ9Il9SZWN0YW5nbGVfNSIgZGF0YS1uYW1lPSImbHQ7UmVjdGFuZ2xlJmd0OyIgY2xhc3M9ImNscy05IiB4PSI0Ny42OSIgd2lkdGg9IjE0My40NSIgaGVpZ2h0PSIxMzAuMzQiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNzkuMTYiIHkxPSIxNi4xOCIgeDI9IjExNy4yNCIgeTI9IjE2LjE4Ii8+PGxpbmUgY2xhc3M9ImNscy0xMCIgeDE9IjYyLjkzIiB5MT0iMTYuMTgiIHgyPSI3Mi42IiB5Mj0iMTYuMTgiLz48bGluZSBjbGFzcz0iY2xzLTExIiB4MT0iNzkuMTYiIHkxPSIyNi45NSIgeDI9IjExNy4yNCIgeTI9IjI2Ljk1Ii8+PGxpbmUgY2xhc3M9ImNscy0xMCIgeDE9IjYyLjkzIiB5MT0iMjYuOTUiIHgyPSI3Mi42IiB5Mj0iMjYuOTUiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNzkuMTYiIHkxPSIzNy43MiIgeDI9IjE1MC43IiB5Mj0iMzcuNzIiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNjIuOTMiIHkxPSIzNy43MiIgeDI9IjcyLjYiIHkyPSIzNy43MiIvPjxsaW5lIGNsYXNzPSJjbHMtMTEiIHgxPSIxNTAuNyIgeTE9IjQ4LjQ5IiB4Mj0iMTc1LjU5IiB5Mj0iNDguNDkiLz48bGluZSBjbGFzcz0iY2xzLTEyIiB4MT0iMTEwLjMyIiB5MT0iNDguNDkiIHgyPSIxNDMuMDUiIHkyPSI0OC40OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTEiIHgxPSI3OS4xNiIgeTE9IjQ4LjQ5IiB4Mj0iMTAxLjM3IiB5Mj0iNDguNDkiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNjIuOTMiIHkxPSI0OC40OSIgeDI9IjcyLjYiIHkyPSI0OC40OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI3OS4xNiIgeTE9IjU5LjI2IiB4Mj0iMTUwLjciIHkyPSI1OS4yNiIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI2Mi45MyIgeTE9IjU5LjI2IiB4Mj0iNzIuNiIgeTI9IjU5LjI2Ii8+PGxpbmUgY2xhc3M9ImNscy0xMCIgeDE9Ijc5LjE2IiB5MT0iNzAuMDMiIHgyPSIxNzUuNTkiIHkyPSI3MC4wMyIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI2Mi45MyIgeTE9IjcwLjAzIiB4Mj0iNzIuNiIgeTI9IjcwLjAzIi8+PGxpbmUgY2xhc3M9ImNscy0xMSIgeDE9Ijc5LjE2IiB5MT0iODAuNzkiIHgyPSIxMTcuMjQiIHkyPSI4MC43OSIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI2Mi45MyIgeTE9IjgwLjc5IiB4Mj0iNzIuNiIgeTI9IjgwLjc5Ii8+PGxpbmUgY2xhc3M9ImNscy0xMyIgeDE9Ijc5LjE2IiB5MT0iOTEuNTYiIHgyPSIxNDkuMDYiIHkyPSI5MS41NiIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI2Mi45MyIgeTE9IjkxLjU2IiB4Mj0iNzIuNiIgeTI9IjkxLjU2Ii8+PGxpbmUgY2xhc3M9ImNscy0xMCIgeDE9IjYyLjkzIiB5MT0iODAuNzkiIHgyPSI3Mi42IiB5Mj0iODAuNzkiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNjIuOTMiIHkxPSI5MS41NiIgeDI9IjcyLjYiIHkyPSI5MS41NiIvPjxsaW5lIGNsYXNzPSJjbHMtMTEiIHgxPSI3OS4xNiIgeTE9IjEwMi4zMyIgeDI9IjExNy4yNCIgeTI9IjEwMi4zMyIvPjxsaW5lIGNsYXNzPSJjbHMtMTAiIHgxPSI2Mi45MyIgeTE9IjEwMi4zMyIgeDI9IjcyLjYiIHkyPSIxMDIuMzMiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iMTI1Ljk4IiB5MT0iMTEzLjEiIHgyPSIxNDkuMDYiIHkyPSIxMTMuMSIvPjxsaW5lIGNsYXNzPSJjbHMtMTIiIHgxPSI3OS4xNiIgeTE9IjExMy4xIiB4Mj0iMTE3LjI0IiB5Mj0iMTEzLjEiLz48bGluZSBjbGFzcz0iY2xzLTEwIiB4MT0iNjIuOTMiIHkxPSIxMTMuMSIgeDI9IjcyLjYiIHkyPSIxMTMuMSIvPjwvZz48L2c+PC9zdmc+'", - "body": "\nEndpoints that return collections of objects should always apply pagination.\nPaginated collections are always wrapped in the following wrapper object:\n\n```json\n{\n \"size\": 5421,\n \"page\": 2,\n \"pagelen\": 10,\n \"next\": \"https://api.bitbucket.org/2.0/repositories/pypy/pypy/commits?page=3\",\n \"previous\": \"https://api.bitbucket.org/2.0/repositories/pypy/pypy/commits?page=1\",\n \"values\": [\n ...\n ]\n}\n```\n\nPagination is often page-bound, with a query parameter page indicating which\npage is to be returned.\n\nHowever, clients are not expected to construct URLs themselves by manipulating\nthe page number query parameter. Instead, the response contains a link to the\nnext page. This link should be treated as an opaque location that is not to be\nconstructed by clients or even assumed to be predictable. The only contract\naround the next link is that it will return the next chunk of results.\n\nLack of a next link in the response indicates the end of the collection.\n\nThe paginated response contains the following fields:\n\n| Field | Value |\n|------------|----------|\n| `size` | Total number of objects in the response. This is an optional element that is not provided in all responses, as it can be expensive to compute. |\n| `page` | Page number of the current results. This is an optional element that is not provided in all responses. |\n| `pagelen` | Current number of objects on the existing page. Globally, the minimum length is 10 and the maximum is 100. Some APIs may specify a different default. |\n| `next` | Link to the next page if it exists. The last page of a collection does not have this value. Use this link to navigate the result set and refrain from constructing your own URLs. |\n| `previous` | Link to previous page if it exists. A collections first page does not have this value. This is an optional element that is not provided in all responses. Some result sets strictly support forward navigation and never provide previous links. Clients must anticipate that backwards navigation is not always available. Use this link to navigate the result set and refrain from constructing your own URLs. |\n| `values` | The list of objects. This contains at most `pagelen` objects. |\n\nThe link to the next page is included such that you don't have to hardcode or construct any links. Only values and next are guaranteed (except the last page, which lacks next). This is because the previous and size values can be expensive for some data sets.\n\nIt is important to realize that Bitbucket support both list-based pagination and iterator-based pagination. List-based pagination assumes that the collection is a discrete, immutable, consistently ordered, finite array of objects with a fixed size. Clients navigate a list-based collection by requesting offset-based chunks. In Bitbucket Cloud, list-based responses include the optional size, page, and previous element. The the next and previous links typically resemble something like /foo/bar?page=4.\n\nHowever, not all result sets can be treated as immutable and finite – much like how programming languages tend to distinguish between lists and arrays on one hand and iterators or stream on the other. Where an list-based pagination offers random access into any point in a collection, iterator-based pagination can only navigate forward one element at a time. In Bitbucket such iterator-based pagination contains the next link and pagelen elements, but not necessarily anything else. In these cases, the next link's value often contains an unpredictable hash instead of an explicit page number. The commits resource uses iterator-based pagination.\n" + "body": "\nEndpoints that return collections of objects should always apply pagination.\nPaginated collections are always wrapped in the following wrapper object:\n\n```json\n{\n \"size\": 5421,\n \"page\": 2,\n \"pagelen\": 10,\n \"next\": \"https://api.bitbucket.org/2.0/repositories/pypy/pypy/commits?page=3\",\n \"previous\": \"https://api.bitbucket.org/2.0/repositories/pypy/pypy/commits?page=1\",\n \"values\": [\n ...\n ]\n}\n```\n\nPagination is often page-bound, with a query parameter page indicating which\npage is to be returned.\n\nHowever, clients are not expected to construct URLs themselves by manipulating\nthe page number query parameter. Instead, the response contains a link to the\nnext page. This link should be treated as an opaque location that is not to be\nconstructed by clients or even assumed to be predictable. The only contract\naround the next link is that it will return the next chunk of results.\n\nLack of a next link in the response indicates the end of the collection.\n\nThe paginated response contains the following fields:\n\n| Field | Value |\n|------------|----------|\n| `size` | Total number of objects in the response. This is an optional element that is not provided in all responses, as it can be expensive to compute. |\n| `page` | Page number of the current results. This is an optional element that is not provided in all responses. |\n| `pagelen` | Current number of objects on the existing page. Globally, the minimum length is 10 and the maximum is 100. Some APIs may specify a different default. |\n| `next` | Link to the next page if it exists. The last page of a collection does not have this value. Use this link to navigate the result set and refrain from constructing your own URLs. |\n| `previous` | Link to previous page if it exists. A collections first page does not have this value. This is an optional element that is not provided in all responses. Some result sets strictly support forward navigation and never provide previous links. Clients must anticipate that backwards navigation is not always available. Use this link to navigate the result set and refrain from constructing your own URLs. |\n| `values` | The list of objects. This contains at most `pagelen` objects. |\n\nThe link to the next page is included such that you don't have to hardcode or construct any links. Only values and next are guaranteed (except the last page, which lacks next). This is because the previous and size values can be expensive for some data sets.\n\nIt is important to realize that Bitbucket support both list-based pagination and iterator-based pagination. List-based pagination assumes that the collection is a discrete, immutable, consistently ordered, finite array of objects with a fixed size. Clients navigate a list-based collection by requesting offset-based chunks. In Bitbucket Cloud, list-based responses include the optional size, page, and previous element. The next and previous links typically resemble something like /foo/bar?page=4.\n\nHowever, not all result sets can be treated as immutable and finite – much like how programming languages tend to distinguish between lists and arrays on one hand and iterators or stream on the other. Where an list-based pagination offers random access into any point in a collection, iterator-based pagination can only navigate forward one element at a time. In Bitbucket such iterator-based pagination contains the next link and pagelen elements, but not necessarily anything else. In these cases, the next link's value often contains an unpredictable hash instead of an explicit page number. The commits resource uses iterator-based pagination.\n" }, { "anchor": "partial-response", diff --git a/plugins/bitbucket-cloud-common/package.json b/plugins/bitbucket-cloud-common/package.json index 202b7a7499..9a9099e5db 100644 --- a/plugins/bitbucket-cloud-common/package.json +++ b/plugins/bitbucket-cloud-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-bitbucket-cloud-common", - "version": "0.2.25-next.0", + "version": "0.2.26-next.1", "description": "Common functionalities for bitbucket-cloud plugins", "backstage": { "role": "common-library", diff --git a/plugins/catalog-backend-module-aws/CHANGELOG.md b/plugins/catalog-backend-module-aws/CHANGELOG.md index 0a36b166ae..07a4438b6e 100644 --- a/plugins/catalog-backend-module-aws/CHANGELOG.md +++ b/plugins/catalog-backend-module-aws/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-catalog-backend-module-aws +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.4.5 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.4.5-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-aws/package.json b/plugins/catalog-backend-module-aws/package.json index 0ea555993a..c2f1e3f34b 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.5-next.3", + "version": "0.4.6-next.2", "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 bb7c9bfec4..ebb1fe39c4 100644 --- a/plugins/catalog-backend-module-azure/CHANGELOG.md +++ b/plugins/catalog-backend-module-azure/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-catalog-backend-module-azure +## 0.3.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.3.0-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.3.0-next.0 + +### Minor Changes + +- 277092a: Added the Azure Blob Storage as catalog entity provider to import all the desired entities from storage account provided in app-config.yaml + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-azure/package.json b/plugins/catalog-backend-module-azure/package.json index be315417c8..389bc1cfc9 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.2.4-next.2", + "version": "0.3.0-next.2", "description": "A Backstage catalog backend module that helps integrate towards Azure", "backstage": { "role": "backend-plugin-module", @@ -51,12 +51,13 @@ "test": "backstage-cli package test" }, "dependencies": { + "@azure/identity": "^4.0.0", + "@azure/storage-blob": "^12.5.0", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-azure/report.api.md b/plugins/catalog-backend-module-azure/report.api.md index d11197d7f2..60b7ee135b 100644 --- a/plugins/catalog-backend-module-azure/report.api.md +++ b/plugins/catalog-backend-module-azure/report.api.md @@ -56,6 +56,6 @@ export class AzureDevOpsEntityProvider implements EntityProvider { } // @public -const catalogModuleAzureDevOpsEntityProvider: BackendFeature; -export default catalogModuleAzureDevOpsEntityProvider; +const catalogModuleAzureEntityProvider: BackendFeature; +export default catalogModuleAzureEntityProvider; ``` diff --git a/plugins/catalog-backend-module-azure/src/lib/azure.ts b/plugins/catalog-backend-module-azure/src/lib/azure.ts index 3bdff90110..0b0d89c15b 100644 --- a/plugins/catalog-backend-module-azure/src/lib/azure.ts +++ b/plugins/catalog-backend-module-azure/src/lib/azure.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import fetch from 'node-fetch'; import { AzureDevOpsCredentialsProvider, AzureIntegrationConfig, diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts index 32eb190460..9c5d1baef7 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts @@ -17,8 +17,11 @@ import { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { catalogModuleAzureDevOpsEntityProvider } from './catalogModuleAzureDevOpsEntityProvider'; -import { AzureDevOpsEntityProvider } from '../providers'; +import { catalogModuleAzureEntityProvider } from './catalogModuleAzureDevOpsEntityProvider'; +import { + AzureBlobStorageEntityProvider, + AzureDevOpsEntityProvider, +} from '../providers'; describe('catalogModuleAzureDevOpsEntityProvider', () => { it('should register provider at the catalog extension point', async () => { @@ -58,7 +61,7 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], features: [ - catalogModuleAzureDevOpsEntityProvider, + catalogModuleAzureEntityProvider, mockServices.rootConfig.factory({ data: config }), mockServices.logger.factory(), scheduler.factory, @@ -73,4 +76,63 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { ); expect(runner).not.toHaveBeenCalled(); }); + + it('should register azure blob storage provider at the catalog extension point', async () => { + let addedProviders: Array | undefined; + let usedSchedule: SchedulerServiceTaskScheduleDefinition | undefined; + + const extensionPoint = { + addEntityProvider: (providers: any) => { + addedProviders = providers; + }, + }; + const runner = jest.fn(); + const scheduler = mockServices.scheduler.mock({ + createScheduledTaskRunner(schedule) { + usedSchedule = schedule; + return { run: runner }; + }, + }); + + const config = { + integrations: { + azureBlobStorage: [ + { + accountName: 'test', + accountKey: 'test', + }, + ], + }, + catalog: { + providers: { + azureBlob: { + containerName: 'test', + accountName: 'test', + schedule: { + frequency: 'P1M', + timeout: 'PT3M', + }, + }, + }, + }, + }; + + await startTestBackend({ + extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + features: [ + catalogModuleAzureEntityProvider, + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + scheduler.factory, + ], + }); + + expect(usedSchedule?.frequency).toEqual({ months: 1 }); + expect(usedSchedule?.timeout).toEqual({ minutes: 3 }); + expect(addedProviders?.length).toEqual(1); + expect(addedProviders?.pop()?.getProviderName()).toEqual( + 'azureBlobStorage-provider:default', + ); + expect(runner).not.toHaveBeenCalled(); + }); }); diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts index 3aaa1b5b08..cc808292f3 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts @@ -19,16 +19,19 @@ import { createBackendModule, } from '@backstage/backend-plugin-api'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; -import { AzureDevOpsEntityProvider } from '../providers'; +import { + AzureBlobStorageEntityProvider, + AzureDevOpsEntityProvider, +} from '../providers'; /** * Registers the AzureDevOpsEntityProvider with the catalog processing extension point. * * @public */ -export const catalogModuleAzureDevOpsEntityProvider = createBackendModule({ +export const catalogModuleAzureEntityProvider = createBackendModule({ pluginId: 'catalog', - moduleId: 'azure-dev-ops-entity-provider', + moduleId: 'azure-providers', register(env) { env.registerInit({ deps: { @@ -38,12 +41,25 @@ export const catalogModuleAzureDevOpsEntityProvider = createBackendModule({ scheduler: coreServices.scheduler, }, async init({ config, catalog, logger, scheduler }) { - catalog.addEntityProvider( - AzureDevOpsEntityProvider.fromConfig(config, { - logger, - scheduler, - }), - ); + // Check for Azure Blob Storage provider configuration and register it + if (config.has('catalog.providers.azureBlob')) { + catalog.addEntityProvider( + AzureBlobStorageEntityProvider.fromConfig(config, { + logger, + scheduler, + }), + ); + } + + // Check for Azure DevOps provider configuration and register it + if (config.has('catalog.providers.azureDevOps')) { + catalog.addEntityProvider( + AzureDevOpsEntityProvider.fromConfig(config, { + logger, + scheduler, + }), + ); + } }, }); }, diff --git a/plugins/catalog-backend-module-azure/src/module/index.ts b/plugins/catalog-backend-module-azure/src/module/index.ts index 329ad604e2..6e560cf17f 100644 --- a/plugins/catalog-backend-module-azure/src/module/index.ts +++ b/plugins/catalog-backend-module-azure/src/module/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { catalogModuleAzureDevOpsEntityProvider as default } from './catalogModuleAzureDevOpsEntityProvider'; +export { catalogModuleAzureEntityProvider as default } from './catalogModuleAzureDevOpsEntityProvider'; diff --git a/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.test.ts new file mode 100644 index 0000000000..62b635d26e --- /dev/null +++ b/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.test.ts @@ -0,0 +1,238 @@ +/* + * 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 { + SchedulerService, + SchedulerServiceTaskRunner, + SchedulerServiceTaskInvocationDefinition, +} from '@backstage/backend-plugin-api'; +import { ConfigReader } from '@backstage/config'; +import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; +import { AzureBlobStorageEntityProvider } from './AzureBlobStorageEntityProvider'; +import { mockServices } from '@backstage/backend-test-utils'; + +class PersistingTaskRunner implements SchedulerServiceTaskRunner { + private tasks: SchedulerServiceTaskInvocationDefinition[] = []; + + getTasks() { + return this.tasks; + } + + run(task: SchedulerServiceTaskInvocationDefinition): Promise { + this.tasks.push(task); + return Promise.resolve(undefined); + } +} + +const blobs = ['key1.yaml', 'key2.yaml', 'key3.yaml', 'key4.yaml']; +const createBlobList = (blobsArray: string[]) => { + return blobsArray.map(blob => ({ + name: blob, + })); +}; +// Mocking Azure Storage Blob Library +jest.mock('@azure/storage-blob', () => { + return { + BlobServiceClient: jest.fn().mockImplementation(() => ({ + url: 'https://myaccount.blob.core.windows.net/', + getContainerClient: jest.fn().mockImplementation(() => ({ + // eslint-disable-next-line func-names + listBlobsFlat: jest.fn(async function* () { + yield* createBlobList(blobs); + }), + })), + })), + }; +}); + +const logger = mockServices.logger.mock(); + +describe('AzureBlobStorageEntityProvider', () => { + const containerName = 'container-1'; + const accountName = 'myaccount'; + const expectMutation = async ( + providerId: string, + providerConfig: object, + expectedBaseUrl: string, + integrationConfig?: object, + scheduleInConfig?: boolean, + ) => { + const config = new ConfigReader({ + integrations: { + azureBlobStorage: integrationConfig ? [integrationConfig] : [], + }, + catalog: { + providers: { + azureBlob: { + [providerId]: providerConfig, + }, + }, + }, + }); + + const schedulingConfig: Record = {}; + const normalizedExpectedBaseUrl = expectedBaseUrl.endsWith('/') + ? expectedBaseUrl + : `${expectedBaseUrl}/`; + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + + if (scheduleInConfig) { + schedulingConfig.scheduler = { + createScheduledTaskRunner: (_: any) => schedule, + } as unknown as SchedulerService; + } else { + schedulingConfig.schedule = schedule; + } + + const provider = AzureBlobStorageEntityProvider.fromConfig(config, { + ...schedulingConfig, + logger, + })[0]; + + expect(provider.getProviderName()).toEqual( + `azureBlobStorage-provider:${providerId}`, + ); + + try { + await provider.connect(entityProviderConnection); + } catch (error) { + console.error('Error during provider connection:', error); + } + + const taskDef = schedule.getTasks()[0]; + expect(taskDef.id).toEqual( + `azureBlobStorage-provider:${providerId}:refresh`, + ); + + await (taskDef.fn as () => Promise)(); + + const expectedEntities = blobs.map(blob => { + const url = encodeURI(`${normalizedExpectedBaseUrl}${blob}`); + return { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Location', + metadata: { + annotations: { + 'backstage.io/managed-by-location': `url:${url}`, + 'backstage.io/managed-by-origin-location': `url:${url}`, + }, + name: expect.stringMatching(/generated-[a-f0-9]{40}/), + }, + spec: { + presence: 'required', + target: `${url}`, + type: 'url', + }, + }, + locationKey: `azureBlobStorage-provider:${providerId}`, + }; + }); + + expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({ + type: 'full', + entities: expectedEntities, + }); + }; + + // eslint-disable-next-line jest/expect-expect + it('apply full update on scheduled execution', async () => { + return expectMutation( + 'staticContainer', + { + containerName, + accountName, + }, + 'https://myaccount.blob.core.windows.net/container-1/', + { + accountName: 'myaccount', + }, + ); + }); + + // eslint-disable-next-line jest/expect-expect + it('apply full update no prefix', async () => { + return expectMutation( + 'staticContainerNoPrefix', + { + containerName, + accountName, + schedule: { + frequency: { minutes: 30 }, + timeout: { minutes: 3 }, + }, + }, + 'https://myaccount.blob.core.windows.net/container-1/', + { + host: 'blob.core.windows.net', + accountName: 'myaccount', + }, + ); + }); + + it('fail without schedule and scheduler', () => { + const config = new ConfigReader({ + catalog: { + providers: { + azureBlob: { + test: { + accountName: 'myaccount', + containerName: 'container-1', + prefix: 'sub/dir/', + }, + }, + }, + }, + }); + + expect(() => + AzureBlobStorageEntityProvider.fromConfig(config, { + logger, + }), + ).toThrow('Either schedule or scheduler must be provided'); + }); + + it('fail with scheduler but no schedule config', () => { + const scheduler = { + createScheduledTaskRunner: (_: any) => jest.fn(), + } as unknown as SchedulerService; + const config = new ConfigReader({ + catalog: { + providers: { + azureBlob: { + test: { + containerName: 'container-1', + prefix: 'sub/dir/', + accountName: 'myaccount', + }, + }, + }, + }, + }); + + expect(() => + AzureBlobStorageEntityProvider.fromConfig(config, { + logger, + scheduler, + }), + ).toThrow( + 'No schedule provided neither via code nor config for AzureBlobStorageEntityProvider:test.', + ); + }); +}); diff --git a/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.ts b/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.ts new file mode 100644 index 0000000000..ae2fbcb3ff --- /dev/null +++ b/plugins/catalog-backend-module-azure/src/providers/AzureBlobStorageEntityProvider.ts @@ -0,0 +1,241 @@ +/* + * Copyright 2022 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 { + AnonymousCredential, + BlobServiceClient, + ContainerClient, + StorageSharedKeyCredential, +} from '@azure/storage-blob'; +import { Config } from '@backstage/config'; +import { + LoggerService, + SchedulerService, + SchedulerServiceTaskRunner, +} from '@backstage/backend-plugin-api'; +import { + EntityProvider, + EntityProviderConnection, + locationSpecToLocationEntity, +} from '@backstage/plugin-catalog-node'; +import { LocationSpec } from '@backstage/plugin-catalog-common'; +import * as uuid from 'uuid'; +import { readAzureBlobStorageConfigs } from './config'; +import { + AzureBlobStorageIntergation, + DefaultAzureCredentialsManager, + ScmIntegrations, +} from '@backstage/integration'; +import { TokenCredential } from '@azure/identity'; +import { AzureBlobStorageConfig } from './types'; + +/** + * Provider which discovers catalog files within an Azure Storage accounts. + * + * Use `AzureBlobStorageEntityProvider.fromConfig(...)` to create instances. + * + * @public + */ +export class AzureBlobStorageEntityProvider implements EntityProvider { + private readonly logger: LoggerService; + private connection?: EntityProviderConnection; + private blobServiceClient?: BlobServiceClient; + private readonly scheduleFn: () => Promise; + + static fromConfig( + configRoot: Config, + options: { + logger: LoggerService; + schedule?: SchedulerServiceTaskRunner; + scheduler?: SchedulerService; + }, + ): AzureBlobStorageEntityProvider[] { + const providerConfigs = readAzureBlobStorageConfigs(configRoot); + + const scmIntegration = ScmIntegrations.fromConfig(configRoot); + const credentialsProvider = + DefaultAzureCredentialsManager.fromIntegrations(scmIntegration); + if (!options.schedule && !options.scheduler) { + throw new Error('Either schedule or scheduler must be provided.'); + } + + return providerConfigs.map(providerConfig => { + const integration = scmIntegration.azureBlobStorage + .list() + .filter( + azureIntegration => + azureIntegration.config.accountName === providerConfig.accountName, + )[0]; + + if (!options.schedule && !providerConfig.schedule) { + throw new Error( + `No schedule provided neither via code nor config for AzureBlobStorageEntityProvider:${providerConfig.id}.`, + ); + } + + if (!integration) { + throw new Error( + `There is no Azure blob storage integration for account. Please add a configuration entry for it under integrations.azureBlobStorage`, + ); + } + + const taskRunner = + options.schedule ?? + options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!); + + return new AzureBlobStorageEntityProvider( + providerConfig, + integration, + credentialsProvider, + options.logger, + taskRunner, + ); + }); + } + private constructor( + private readonly config: AzureBlobStorageConfig, + private readonly integration: AzureBlobStorageIntergation, + private readonly credentialsProvider: DefaultAzureCredentialsManager, + logger: LoggerService, + schedule: SchedulerServiceTaskRunner, + ) { + this.logger = logger.child({ target: this.getProviderName() }); + this.scheduleFn = this.createScheduleFn(schedule); + } + + private createScheduleFn( + taskRunner: SchedulerServiceTaskRunner, + ): () => Promise { + return async () => { + const taskId = `${this.getProviderName()}:refresh`; + return taskRunner.run({ + id: taskId, + fn: async () => { + const logger = this.logger.child({ + class: AzureBlobStorageEntityProvider.prototype.constructor.name, + taskId, + taskInstanceId: uuid.v4(), + }); + + try { + await this.refresh(logger); + } catch (error) { + logger.error( + `${this.getProviderName()} refresh failed, ${error}`, + error, + ); + } + }, + }); + }; + } + + getProviderName(): string { + return `azureBlobStorage-provider:${this.config.id}`; + } + + async connect(connection: EntityProviderConnection): Promise { + this.connection = connection; + let credential: + | TokenCredential + | StorageSharedKeyCredential + | AnonymousCredential; + if (this.integration.config.accountKey) { + credential = new StorageSharedKeyCredential( + this.integration.config.accountName as string, + this.integration.config.accountKey as string, + ); // StorageSharedKeyCredential is only allowed in node.js runtime not in browser + } else { + credential = await this.credentialsProvider.getCredentials( + this.integration.config.accountName as string, + ); + } + let blobServiceClientUrl: string; + + if (this.integration.config.endpoint) { + if (this.integration.config.sasToken) { + blobServiceClientUrl = `${this.integration.config.endpoint}?${this.integration.config.sasToken}`; + } else { + blobServiceClientUrl = `${this.integration.config.endpoint}`; + } + } else { + blobServiceClientUrl = `https://${this.integration.config.accountName}.${this.integration.config.host}`; + } + + this.blobServiceClient = new BlobServiceClient( + blobServiceClientUrl, + credential, + ); + await this.scheduleFn(); + } + + async refresh(logger: LoggerService) { + if (!this.connection) { + throw new Error('Not initialized'); + } + + logger.info('Discovering Azure Blob Storage blobs'); + + const keys = await this.listAllBlobKeys(); + logger.info(`Discovered ${keys.length} Azure Blob Storage blobs`); + + const locations = keys.map(key => this.createLocationSpec(key)); + + await this.connection.applyMutation({ + type: 'full', + entities: locations.map(location => { + return { + locationKey: this.getProviderName(), + entity: locationSpecToLocationEntity({ location }), + }; + }), + }); + + logger.info( + `Committed ${locations.length} Locations for Azure Blob Storage blobs`, + ); + } + + private async listAllBlobKeys(): Promise { + const keys: string[] = []; + const containerClient = this.blobServiceClient?.getContainerClient( + this.config.containerName, + ); + + for await (const blob of ( + containerClient as ContainerClient + ).listBlobsFlat()) { + if (blob.name) { + keys.push(blob.name); + } + } + + return keys; + } + + private createLocationSpec(key: string): LocationSpec { + return { + type: 'url', + target: this.createObjectUrl(key), + presence: 'required', + }; + } + + private createObjectUrl(key: string): string { + const endpoint = this.blobServiceClient?.url; + return `${endpoint}${this.config.containerName}/${key}`; + } +} diff --git a/plugins/catalog-backend-module-azure/src/providers/config.test.ts b/plugins/catalog-backend-module-azure/src/providers/config.test.ts index 5d5ae930c1..78ed559749 100644 --- a/plugins/catalog-backend-module-azure/src/providers/config.test.ts +++ b/plugins/catalog-backend-module-azure/src/providers/config.test.ts @@ -15,7 +15,7 @@ */ import { ConfigReader } from '@backstage/config'; -import { readAzureDevOpsConfigs } from './config'; +import { readAzureBlobStorageConfigs, readAzureDevOpsConfigs } from './config'; describe('readAzureDevOpsConfigs', () => { it('reads all provider configs and set default values', () => { @@ -106,3 +106,74 @@ describe('readAzureDevOpsConfigs', () => { }); }); }); + +describe('readAzureBlobStorageConfigs', () => { + it('reads single and multiple Azure Blob Storage provider configs', () => { + const provider1 = { + accountName: 'account-1', + containerName: 'container-1', + schedule: { + frequency: 'PT30M', + timeout: { + minutes: 3, + }, + }, + }; + const provider2 = { + accountName: 'account-1', + containerName: 'container-2', + }; + + const configSingle = { + catalog: { + providers: { + azureBlob: provider2, + }, + }, + }; + + const configMulti = { + catalog: { + providers: { + azureBlob: { + provider1, + provider2, + }, + }, + }, + }; + + // Single provider case + const actualSingle = readAzureBlobStorageConfigs( + new ConfigReader(configSingle), + ); + expect(actualSingle).toHaveLength(1); + expect(actualSingle[0]).toEqual({ + id: 'default', + accountName: 'account-1', + containerName: 'container-2', + schedule: undefined, // no schedule provided in this case + }); + + // Multiple providers case + const actualMulti = readAzureBlobStorageConfigs( + new ConfigReader(configMulti), + ); + expect(actualMulti).toHaveLength(2); + expect(actualMulti[0]).toEqual({ + id: 'provider1', + accountName: 'account-1', + containerName: 'container-1', + schedule: { + ...provider1.schedule, + frequency: { minutes: 30 }, + }, + }); + expect(actualMulti[1]).toEqual({ + id: 'provider2', + accountName: 'account-1', + containerName: 'container-2', + schedule: undefined, // no schedule provided + }); + }); +}); diff --git a/plugins/catalog-backend-module-azure/src/providers/config.ts b/plugins/catalog-backend-module-azure/src/providers/config.ts index 17616b06bc..8ec1cbfb1b 100644 --- a/plugins/catalog-backend-module-azure/src/providers/config.ts +++ b/plugins/catalog-backend-module-azure/src/providers/config.ts @@ -16,7 +16,9 @@ import { readSchedulerServiceTaskScheduleDefinitionFromConfig } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; -import { AzureDevOpsConfig } from './types'; +import { AzureDevOpsConfig, AzureBlobStorageConfig } from './types'; + +const DEFAULT_PROVIDER_ID = 'default'; export function readAzureDevOpsConfigs(config: Config): AzureDevOpsConfig[] { const configs: AzureDevOpsConfig[] = []; @@ -61,3 +63,52 @@ function readAzureDevOpsConfig(id: string, config: Config): AzureDevOpsConfig { schedule, }; } + +export function readAzureBlobStorageConfigs( + config: Config, +): AzureBlobStorageConfig[] { + const configs: AzureBlobStorageConfig[] = []; + + const providerConfigs = config.getOptionalConfig( + 'catalog.providers.azureBlob', + ); + + if (!providerConfigs) { + return configs; + } + + if (providerConfigs.has('containerName')) { + // simple/single config variant + configs.push( + readAzureBlobStorageConfig(DEFAULT_PROVIDER_ID, providerConfigs), + ); + + return configs; + } + + for (const id of providerConfigs.keys()) { + configs.push(readAzureBlobStorageConfig(id, providerConfigs.getConfig(id))); + } + + return configs; +} + +function readAzureBlobStorageConfig( + id: string, + config: Config, +): AzureBlobStorageConfig { + const containerName = config.getString('containerName'); + const accountName = config.getString('accountName'); + const schedule = config.has('schedule') + ? readSchedulerServiceTaskScheduleDefinitionFromConfig( + config.getConfig('schedule'), + ) + : undefined; + + return { + id, + containerName, + accountName, + schedule, + }; +} diff --git a/plugins/catalog-backend-module-azure/src/providers/index.ts b/plugins/catalog-backend-module-azure/src/providers/index.ts index 450fc0af27..5c9616e162 100644 --- a/plugins/catalog-backend-module-azure/src/providers/index.ts +++ b/plugins/catalog-backend-module-azure/src/providers/index.ts @@ -15,3 +15,4 @@ */ export { AzureDevOpsEntityProvider } from './AzureDevOpsEntityProvider'; +export { AzureBlobStorageEntityProvider } from './AzureBlobStorageEntityProvider'; diff --git a/plugins/catalog-backend-module-azure/src/providers/types.ts b/plugins/catalog-backend-module-azure/src/providers/types.ts index 5ca9dc94dc..e296d50ca7 100644 --- a/plugins/catalog-backend-module-azure/src/providers/types.ts +++ b/plugins/catalog-backend-module-azure/src/providers/types.ts @@ -26,3 +26,10 @@ export type AzureDevOpsConfig = { path: string; schedule?: SchedulerServiceTaskScheduleDefinition; }; + +export type AzureBlobStorageConfig = { + id: string; + containerName: string; + accountName: string; + schedule?: SchedulerServiceTaskScheduleDefinition; +}; diff --git a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md index fbae7e340e..c7e9b52de4 100644 --- a/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-backstage-openapi/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-catalog-backend-module-backstage-openapi +## 0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + +## 0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.4.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.4.2-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-backstage-openapi/package.json b/plugins/catalog-backend-module-backstage-openapi/package.json index 608b532d0a..191e1567d7 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.4.2-next.2", + "version": "0.4.3-next.2", "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 32670276bb..082ba8461e 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/plugin-catalog-backend-module-bitbucket-cloud +## 0.4.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.4.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.4.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.4.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- f6b4b8a: Implemented discovery on project-level to shift Bitbucket Cloud API limits +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.4.2-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-cloud/package.json b/plugins/catalog-backend-module-bitbucket-cloud/package.json index a8b074da0f..73bbf48ffd 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.2-next.3", + "version": "0.4.3-next.2", "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 85f3c68faf..d7318f53ea 100644 --- a/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/catalog-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-catalog-backend-module-bitbucket-server +## 0.3.0-next.2 + +### Minor Changes + +- 3f34ea9: Throttles Bitbucket Server API calls + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-bitbucket-server/package.json b/plugins/catalog-backend-module-bitbucket-server/package.json index bafde93f12..f82a7bba16 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.2.4-next.2", + "version": "0.3.0-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", @@ -56,8 +56,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", - "@types/node-fetch": "^2.5.12", - "node-fetch": "^2.7.0", + "p-throttle": "^4.1.1", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-bitbucket-server/report.api.md b/plugins/catalog-backend-module-bitbucket-server/report.api.md index b2a0a9368a..0da9b78139 100644 --- a/plugins/catalog-backend-module-bitbucket-server/report.api.md +++ b/plugins/catalog-backend-module-bitbucket-server/report.api.md @@ -11,7 +11,6 @@ import { EntityProvider } from '@backstage/plugin-catalog-node'; import { EntityProviderConnection } from '@backstage/plugin-catalog-node'; import { LocationSpec } from '@backstage/plugin-catalog-node'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { Response as Response_2 } from 'node-fetch'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api'; @@ -27,7 +26,7 @@ export class BitbucketServerClient { projectKey: string; repo: string; path: string; - }): Promise; + }): Promise; // (undocumented) getRepository(options: { projectKey: string; 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 b5baf66afd..73373ffff1 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/lib/BitbucketServerClient.ts @@ -14,12 +14,24 @@ * limitations under the License. */ -import fetch, { Request, Response } from 'node-fetch'; import { BitbucketServerIntegrationConfig, getBitbucketServerRequestOptions, } from '@backstage/integration'; import { BitbucketServerProject, BitbucketServerRepository } from './types'; +import pThrottle from 'p-throttle'; + +// 1 per second +const throttle = pThrottle({ + limit: 1, + interval: 1000, +}); + +const throttledFetch = throttle( + async (url: RequestInfo, options?: RequestInit) => { + return await fetch(url, options); + }, +); /** * A client for interacting with a Bitbucket Server instance @@ -66,7 +78,7 @@ export class BitbucketServerClient { path: string; }): Promise { const base = new URL(this.config.apiBaseUrl); - return fetch( + return throttledFetch( `${base.protocol}//${base.host}/projects/${options.projectKey}/repos/${options.repo}/raw/${options.path}`, getBitbucketServerRequestOptions(this.config), ); @@ -77,7 +89,7 @@ export class BitbucketServerClient { repo: string; }): Promise { const request = `${this.config.apiBaseUrl}/projects/${options.projectKey}/repos/${options.repo}`; - const response = await fetch( + const response = await throttledFetch( request, getBitbucketServerRequestOptions(this.config), ); @@ -118,16 +130,17 @@ export class BitbucketServerClient { } private async request(req: Request): Promise { - return fetch(req, getBitbucketServerRequestOptions(this.config)).then( - (response: Response) => { - if (!response.ok) { - throw new Error( - `Unexpected response for ${req.method} ${req.url}. Expected 200 but got ${response.status} - ${response.statusText}`, - ); - } - return response; - }, - ); + return throttledFetch( + req, + getBitbucketServerRequestOptions(this.config), + ).then((response: Response) => { + if (!response.ok) { + throw new Error( + `Unexpected response for ${req.method} ${req.url}. Expected 200 but got ${response.status} - ${response.statusText}`, + ); + } + return response; + }); } } diff --git a/plugins/catalog-backend-module-gcp/CHANGELOG.md b/plugins/catalog-backend-module-gcp/CHANGELOG.md index 5f3103839d..b8d319592e 100644 --- a/plugins/catalog-backend-module-gcp/CHANGELOG.md +++ b/plugins/catalog-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-gcp +## 0.3.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## 0.3.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + ## 0.3.2-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gcp/package.json b/plugins/catalog-backend-module-gcp/package.json index f3f2466a9c..be2f0ba442 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.2-next.2", + "version": "0.3.3-next.2", "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 f4aa85e083..2801831552 100644 --- a/plugins/catalog-backend-module-gerrit/CHANGELOG.md +++ b/plugins/catalog-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-gerrit +## 0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-gerrit/package.json b/plugins/catalog-backend-module-gerrit/package.json index 84fb556517..b2c35e14b4 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.2.4-next.2", + "version": "0.2.5-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "catalog", @@ -53,7 +53,6 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts index bd03b90c52..2bd5b4e3ce 100644 --- a/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts +++ b/plugins/catalog-backend-module-gerrit/src/providers/GerritEntityProvider.ts @@ -22,7 +22,6 @@ import { LocationSpec, locationSpecToLocationEntity, } from '@backstage/plugin-catalog-node'; -import fetch, { Response } from 'node-fetch'; import { GerritIntegration, getGerritProjectsApiUrl, diff --git a/plugins/catalog-backend-module-github-org/CHANGELOG.md b/plugins/catalog-backend-module-github-org/CHANGELOG.md index 196ba84c0d..782f70896a 100644 --- a/plugins/catalog-backend-module-github-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-github-org/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-github-org +## 0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.3.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend-module-github@0.7.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.3.4 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend-module-github@0.7.7 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + ## 0.3.4-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-github-org/package.json b/plugins/catalog-backend-module-github-org/package.json index 4b20f70a8c..802b960a83 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.4-next.3", + "version": "0.3.5-next.2", "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 a14f219fc6..a78b623ca4 100644 --- a/plugins/catalog-backend-module-github/CHANGELOG.md +++ b/plugins/catalog-backend-module-github/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-catalog-backend-module-github +## 0.7.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.7.8-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.7.8-next.0 + +### Patch Changes + +- 468bbcc: Pass in a default schedule to the `GithubEntityProvider` if none is provided +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.7.7 + +### Patch Changes + +- 9790c02: Fixed an issue in `GithubOrgEntityProvider` that caused an error when processing teams without a parent. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.7.7-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-github/package.json b/plugins/catalog-backend-module-github/package.json index 16b7544da9..511c4019af 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.7.7-next.3", + "version": "0.7.8-next.2", "description": "A Backstage catalog backend module that helps integrate towards GitHub", "backstage": { "role": "backend-plugin-module", @@ -66,7 +66,6 @@ "git-url-parse": "^15.0.0", "lodash": "^4.17.21", "minimatch": "^9.0.0", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { @@ -74,7 +73,7 @@ "@backstage/cli": "workspace:^", "@types/lodash": "^4.14.151", "luxon": "^3.0.0", - "msw": "^1.0.0" + "msw": "^2.0.0" }, "configSchema": "config.d.ts" } diff --git a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts index 29c8cbc66d..d3be18f489 100644 --- a/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts +++ b/plugins/catalog-backend-module-github/src/analyzers/GithubLocationAnalyzer.test.ts @@ -39,7 +39,7 @@ import { mockServices, } from '@backstage/backend-test-utils'; import { setupServer } from 'msw/node'; -import { rest } from 'msw'; +import { http, HttpResponse } from 'msw'; import { ConfigReader } from '@backstage/config'; const server = setupServer(); @@ -67,10 +67,9 @@ describe('GithubLocationAnalyzer', () => { beforeEach(() => { server.use( - rest.post('http://localhost:7007/locations', async (_, res, ctx) => { - return res( - ctx.status(201), - ctx.json({ + http.post('http://localhost:7007/locations', () => + HttpResponse.json( + { location: 'test', exists: false, entities: [ @@ -100,9 +99,10 @@ describe('GithubLocationAnalyzer', () => { }, }, ], - }), - ); - }), + }, + { status: 201 }, + ), + ), ); octokit.repos.get.mockResolvedValue({ diff --git a/plugins/catalog-backend-module-github/src/lib/github.test.ts b/plugins/catalog-backend-module-github/src/lib/github.test.ts index 9eae9e1161..cbe8d8c525 100644 --- a/plugins/catalog-backend-module-github/src/lib/github.test.ts +++ b/plugins/catalog-backend-module-github/src/lib/github.test.ts @@ -17,7 +17,7 @@ import { registerMswTestHooks } from '@backstage/backend-test-utils'; import { GroupEntity, UserEntity } from '@backstage/catalog-model'; import { graphql as graphqlOctokit } from '@octokit/graphql'; -import { graphql as graphqlMsw } from 'msw'; +import { graphql as graphqlMsw, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; import { TeamTransformer, UserTransformer } from './defaultTransformers'; import { @@ -33,14 +33,13 @@ import { createRemoveEntitiesOperation, createReplaceEntitiesOperation, } from './github'; -import fetch from 'node-fetch'; describe('github', () => { - const graphql = graphqlOctokit.defaults({ request: { fetch } }); - const server = setupServer(); registerMswTestHooks(server); + const graphql = graphqlOctokit.defaults({}); + describe('getOrganizationUsers using defaultUserMapper', () => { it('reads members', async () => { const input: QueryResponse = { @@ -73,7 +72,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('users', () => HttpResponse.json({ data: input })), ); await expect( @@ -136,7 +135,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('users', () => HttpResponse.json({ data: input })), ); await expect( @@ -180,7 +179,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('users', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('users', () => HttpResponse.json({ data: input })), ); const users = await getOrganizationUsers( @@ -255,7 +254,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('teams', () => HttpResponse.json({ data: input })), ); await expect(getOrganizationTeams(graphql, 'a')).resolves.toEqual(output); @@ -355,7 +354,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('teams', () => HttpResponse.json({ data: input })), ); await expect( @@ -435,7 +434,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('teams', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('teams', () => HttpResponse.json({ data: input })), ); const teams = await getOrganizationTeams( @@ -471,7 +470,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('orgs', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('orgs', () => HttpResponse.json({ data: input })), ); await expect(getOrganizationsFromUser(graphql, 'foo')).resolves.toEqual({ @@ -500,7 +499,7 @@ describe('github', () => { }; server.use( - graphqlMsw.query('members', (_req, res, ctx) => res(ctx.data(input))), + graphqlMsw.query('members', () => HttpResponse.json({ data: input })), ); await expect(getTeamMembers(graphql, 'a', 'b')).resolves.toEqual(output); @@ -587,8 +586,8 @@ describe('github', () => { }; server.use( - graphqlMsw.query('repositories', (_req, res, ctx) => - res(ctx.data(input)), + graphqlMsw.query('repositories', () => + HttpResponse.json({ data: input }), ), ); 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 624deaa38e..b7df19c296 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.test.ts @@ -621,22 +621,6 @@ describe('GithubEntityProvider', () => { ).toThrow('Either schedule or scheduler must be provided'); }); - it('fail with scheduler but no schedule config', () => { - const scheduler = { - createScheduledTaskRunner: (_: any) => jest.fn(), - } as unknown as SchedulerService; - const config = createSingleProviderConfig(); - - expect(() => - GithubEntityProvider.fromConfig(config, { - logger, - scheduler, - }), - ).toThrow( - 'No schedule provided neither via code nor config for github-provider:myProvider', - ); - }); - it('single simple provider config with schedule in config', async () => { const schedule = new PersistingTaskRunner(); const scheduler = { diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts index 5c6dc75e48..a18846b157 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProvider.ts @@ -126,12 +126,6 @@ export class GithubEntityProvider implements EntityProvider, EventSubscriber { ); } - if (!options.schedule && !providerConfig.schedule) { - throw new Error( - `No schedule provided neither via code nor config for github-provider:${providerConfig.id}.`, - ); - } - const taskRunner = options.schedule ?? options.scheduler!.createScheduledTaskRunner(providerConfig.schedule!); diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts index 296cbc12df..d00cbc888c 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.test.ts @@ -15,7 +15,10 @@ */ import { ConfigReader } from '@backstage/config'; -import { readProviderConfigs } from './GithubEntityProviderConfig'; +import { + readProviderConfigs, + DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, +} from './GithubEntityProviderConfig'; describe('readProviderConfigs', () => { afterEach(() => jest.resetAllMocks()); @@ -124,7 +127,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[1]).toEqual({ @@ -142,7 +145,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[2]).toEqual({ @@ -160,7 +163,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[3]).toEqual({ @@ -178,7 +181,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[4]).toEqual({ @@ -196,7 +199,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[5]).toEqual({ @@ -214,7 +217,7 @@ describe('readProviderConfigs', () => { }, visibility: undefined, }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[6]).toEqual({ @@ -232,7 +235,7 @@ describe('readProviderConfigs', () => { }, visibility: ['public', 'internal'], }, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, validateLocationsExist: false, }); expect(providerConfigs[7]).toEqual({ @@ -251,7 +254,7 @@ describe('readProviderConfigs', () => { visibility: undefined, }, validateLocationsExist: false, - schedule: undefined, + schedule: DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE, }); expect(providerConfigs[8]).toEqual({ id: 'providerWithSchedule', diff --git a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.ts b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.ts index 073c92701f..2e2592b70a 100644 --- a/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.ts +++ b/plugins/catalog-backend-module-github/src/providers/GithubEntityProviderConfig.ts @@ -23,6 +23,15 @@ import { Config } from '@backstage/config'; const DEFAULT_CATALOG_PATH = '/catalog-info.yaml'; const DEFAULT_PROVIDER_ID = 'default'; +export const DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE = { + frequency: { + hours: 3, + }, + timeout: { + hours: 1, + }, +}; + export type GithubEntityProviderConfig = { id: string; catalogPath: string; @@ -99,7 +108,7 @@ function readProviderConfig( ? readSchedulerServiceTaskScheduleDefinitionFromConfig( config.getConfig('schedule'), ) - : undefined; + : DEFAULT_GITHUB_ENTITY_PROVIDER_CONFIG_SCHEDULE; return { id, diff --git a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md index 762c5ef8e4..f6b29c16a4 100644 --- a/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab-org/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-catalog-backend-module-gitlab-org +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.6.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.1-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.3 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-catalog-backend-module-gitlab@0.5.0 + ## 0.2.3-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab-org/package.json b/plugins/catalog-backend-module-gitlab-org/package.json index 68f9489a31..d0f00076a5 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.3-next.3", + "version": "0.2.4-next.2", "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 6bd97eca92..ba0605d660 100644 --- a/plugins/catalog-backend-module-gitlab/CHANGELOG.md +++ b/plugins/catalog-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-catalog-backend-module-gitlab +## 0.6.0-next.2 + +### Minor Changes + +- 99dce5c: Implemented discovery for top-level groups defined in config.group or if undefined global top-level group in Gitlab + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.5.1-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.5.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.5.0 + +### Minor Changes + +- 1b5fdd9: Extended the configuration with the `includeArchivedRepos` property, which allows including repositories when the project is archived. + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-defaults@0.5.3 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.5.0-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-gitlab/package.json b/plugins/catalog-backend-module-gitlab/package.json index 115bd423dc..75c376a355 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.5.0-next.3", + "version": "0.6.0-next.2", "description": "A Backstage catalog backend module that helps integrate towards GitLab", "backstage": { "role": "backend-plugin-module", @@ -61,7 +61,6 @@ "@backstage/plugin-events-node": "workspace:^", "@gitbeaker/rest": "^40.0.3", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts index 953ade6b7c..041aa5b835 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/handlers.ts @@ -83,7 +83,7 @@ const httpHandlers = [ }), rest.get( - `${apiBaseUrlSaas}/groups/subgroup1/members/all`, + `${apiBaseUrlSaas}/groups/group1%2Fsubgroup1/members/all`, (_req, res, ctx) => { return res(ctx.json(subgroup_saas_users_response)); // To-DO change }, @@ -136,6 +136,22 @@ const httpHandlers = [ // dynamic handlers +// https://docs.gitlab.com/ee/api/groups.html#list-group-details supports encoded path and id +const httpGroupFindByEncodedPathDynamic = all_groups_response.flatMap(group => [ + // Handler for apiBaseUrl + rest.get(`${apiBaseUrl}/groups/${group.full_path}`, (_, res, ctx) => { + return res( + ctx.json(all_groups_response.find(g => g.full_path === group.full_path)), + ); + }), + // Handler for apiSaaSBaseUrl + rest.get(`${apiBaseUrlSaas}/groups/${group.full_path}`, (_, res, ctx) => { + return res( + ctx.json(all_groups_response.find(g => g.full_path === group.full_path)), + ); + }), +]); + const httpGroupFindByIdDynamic = all_groups_response.map(group => { return rest.get(`${apiBaseUrl}/groups/${group.id}`, (_, res, ctx) => { return res(ctx.json(all_groups_response.find(g => g.id === group.id))); @@ -618,4 +634,5 @@ export const handlers = [ ...httpGroupListDescendantProjectsById, ...httpGroupListDescendantProjectsByName, ...graphqlHandlers, + ...httpGroupFindByEncodedPathDynamic, ]; diff --git a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts index 2547015df8..d9914c0d0c 100644 --- a/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts +++ b/plugins/catalog-backend-module-gitlab/src/__testUtils__/mocks.ts @@ -1041,7 +1041,7 @@ export const all_groups_response: GitLabGroup[] = [ { id: 1, name: 'group1', - description: '', + description: 'description1', full_path: 'group1', }, { @@ -1804,6 +1804,7 @@ export const expected_group_user_entity: MockObject[] = [ 'url:https://example.com/group1', 'example.com/team-path': 'group1', }, + description: 'description1', name: 'group1', }, spec: { @@ -2090,6 +2091,7 @@ export const expected_full_org_scan_entities: MockObject[] = [ 'url:https://example.com/group1', 'example.com/team-path': 'group1', }, + description: 'description1', name: 'group1', }, spec: { @@ -2347,7 +2349,7 @@ export const expected_full_members_group_org_scan_entities: MockObject[] = [ name: 'JohnDoe', }, spec: { - memberOf: ['subgroup1'], + memberOf: ['group1', 'subgroup1'], // since #26554 also config.group needs to be here. profile: { displayName: 'John Doe', email: 'john.doe@company.com', @@ -2431,6 +2433,30 @@ export const expected_full_members_group_org_scan_entities: MockObject[] = [ }, locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/group1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1', + 'example.com/team-path': 'group1', + }, + description: 'description1', + name: 'group1', + }, + spec: { + children: [], + profile: { + displayName: 'group1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, { entity: { apiVersion: 'backstage.io/v1alpha1', @@ -2472,7 +2498,7 @@ export const expected_group_members_group_org_scan_entities: MockObject[] = [ name: 'JohnDoe', }, spec: { - memberOf: ['subgroup1'], + memberOf: ['subgroup1', 'group1'], profile: { displayName: 'John Doe', email: 'john.doe@company.com', @@ -2507,6 +2533,30 @@ export const expected_group_members_group_org_scan_entities: MockObject[] = [ }, locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', }, + { + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com/group1', + 'backstage.io/managed-by-origin-location': + 'url:https://example.com/group1', + 'example.com/team-path': 'group1', + }, + name: 'group1', + description: 'description1', + }, + spec: { + children: [], + profile: { + displayName: 'group1', + }, + type: 'team', + }, + }, + locationKey: 'GitlabOrgDiscoveryEntityProvider:test-id', + }, ]; export const all_self_hosted_group1_members: MockObject[] = [ diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index f2ce3d18f8..81ba58db5d 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -13,13 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { getGitLabRequestOptions, GitLabIntegrationConfig, } from '@backstage/integration'; -import fetch from 'node-fetch'; import { LoggerService } from '@backstage/backend-plugin-api'; - import { GitLabDescendantGroupsResponse, GitLabGroup, @@ -166,6 +165,15 @@ export class GitLabClient { return this.pagedRequest(`/groups`, options); } + // https://docs.gitlab.com/ee/api/groups.html#list-group-details + // id can either be group id or encoded full path + async getGroupByPath( + groupPath: string, + options?: CommonListOptions, + ): Promise { + return this.nonPagedRequest(`/groups/${groupPath}`, options); + } + async listDescendantGroups( groupPath: string, ): Promise> { diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts index a15894b236..5f62cedb71 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.test.ts @@ -435,7 +435,7 @@ describe('GitlabOrgDiscoveryEntityProvider - refresh', () => { }); // This should return all members of the self-hosted instance regardless of the group set -> expected_full_members_group_org_scan_entities - // All instance members, but only the group entities below the config.group + // All instance members, but only the group entities of config.group and below (#26554) it('Self-hosted: should get all instance users when restrictUsersToGroup is not set', async () => { const config = new ConfigReader(mock.config_org_group_selfHosted); const schedule = new PersistingTaskRunner(); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts index 277a5a8c51..1fbd2a2a13 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabOrgDiscoveryEntityProvider.ts @@ -366,6 +366,7 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { if (this.gitLabClient.isSelfManaged() && this.config.restrictUsersToGroup) { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; + groups.push(await this.gitLabClient.getGroupByPath(this.config.group)); // adds the parent group for #26554 users = paginated( options => this.gitLabClient.listGroupMembers(this.config.group, options), // calls /groups//members @@ -395,14 +396,18 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { else { groups = (await this.gitLabClient.listDescendantGroups(this.config.group)) .items; + + groups.push(await this.gitLabClient.getGroupByPath(this.config.group)); // adds the parent group for #26554 + const rootGroupSplit = this.config.group.split('/'); - const rootGroup = this.config.restrictUsersToGroup - ? rootGroupSplit[rootGroupSplit.length - 1] + const groupPath = this.config.restrictUsersToGroup + ? this.config.group : rootGroupSplit[0]; + users = paginated( options => this.gitLabClient.listSaaSUsers( - rootGroup, + groupPath, options, this.config.includeUsersWithoutSeat, ), @@ -775,7 +780,8 @@ export class GitlabOrgDiscoveryEntityProvider implements EntityProvider { return ( this.config.groupPattern.test(group.full_path) && (!this.config.group || - group.full_path.startsWith(`${this.config.group}/`)) + group.full_path.startsWith(`${this.config.group}/`) || + group.full_path === this.config.group) ); } diff --git a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md index 7707d16249..5f25c7e4f7 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md +++ b/plugins/catalog-backend-module-incremental-ingestion/CHANGELOG.md @@ -1,5 +1,82 @@ # @backstage/plugin-catalog-backend-module-incremental-ingestion +## 0.6.1-next.2 + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- d42ecb0: Remove backend-common package from incremental-ingestion plugin and update related code +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.6.1-next.1 + +### Patch Changes + +- fe87fbf: Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## 0.6.1-next.0 + +### Patch Changes + +- cce9cae: Deprecate old-backend-system `IncrementalCatalogBuilder` +- 5aa44d2: Wire up the events together in the new backend system +- cbfc69e: Create a `dev/index.ts` entrypoint for `yarn start` +- 3ca5f70: Ensure that the scheduled worker task doesn't run at an unreasonably high frequency +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + +## 0.6.0 + +### Minor Changes + +- 6cf91c5: Use `HumanDuration` for all duration needs in the public API, instead of `luxon` types. These are generally compatible, with a few caveats: + + - If you scheduled things to run quarterly (`quarter` or `quarters`), you can use `{ months: 3 }` instead. + - If you used the singular nouns such as `year: 1`, use plurals instead (e.g. `years: 1`). + +### Patch Changes + +- c5e39e7: Internal refactor to use the deferred from the types package +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.6.0-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-incremental-ingestion/dev/index.ts b/plugins/catalog-backend-module-incremental-ingestion/dev/index.ts new file mode 100644 index 0000000000..cc205c6865 --- /dev/null +++ b/plugins/catalog-backend-module-incremental-ingestion/dev/index.ts @@ -0,0 +1,81 @@ +/* + * 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 { createBackend } from '@backstage/backend-defaults'; +import { + coreServices, + createBackendModule, +} from '@backstage/backend-plugin-api'; +import { mockServices } from '@backstage/backend-test-utils'; +import { + IncrementalEntityProvider, + incrementalIngestionProvidersExtensionPoint, +} from '../src'; + +const dummyProvider = createBackendModule({ + pluginId: 'catalog', + moduleId: 'incremental-test-provider', + register(reg) { + reg.registerInit({ + deps: { + logger: coreServices.logger, + providers: incrementalIngestionProvidersExtensionPoint, + }, + async init({ logger, providers }) { + const provider: IncrementalEntityProvider = { + getProviderName: () => 'test-provider', + around: burst => burst(0), + next: async (_context, cursor) => { + await new Promise(resolve => setTimeout(resolve, 500)); + if (cursor === undefined || cursor < 3) { + logger.info(`### Returning batch #${cursor}`); + return { done: false, entities: [], cursor: (cursor ?? 0) + 1 }; + } + + logger.info('### Last batch reached, stopping'); + return { done: true }; + }, + }; + + providers.addProvider({ + provider: provider, + options: { + burstInterval: { seconds: 1 }, + burstLength: { seconds: 10 }, + restLength: { seconds: 10 }, + }, + }); + }, + }); + }, +}); + +const backend = createBackend(); +backend.add( + mockServices.rootConfig.factory({ + data: { + backend: { + baseUrl: 'http://localhost:7007', + listen: ':7007', + database: { client: 'better-sqlite3', connection: ':memory:' }, + }, + }, + }), +); +backend.add(import('@backstage/plugin-catalog-backend')); +backend.add(import('../src')); +backend.add(dummyProvider); +backend.start(); diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index 2cd06708f4..855973c834 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.6.0-next.3", + "version": "0.6.1-next.2", "description": "An entity provider for streaming large asset sources into the catalog", "backstage": { "role": "backend-plugin-module", @@ -51,7 +51,7 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "^0.25.0", + "@backstage/backend-defaults": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/catalog-model": "workspace:^", "@backstage/config": "workspace:^", @@ -61,6 +61,7 @@ "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^", + "@opentelemetry/api": "^1.9.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", @@ -69,7 +70,6 @@ "uuid": "^11.0.0" }, "devDependencies": { - "@backstage/backend-defaults": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/luxon": "^3.0.0" diff --git a/plugins/catalog-backend-module-incremental-ingestion/report-alpha.api.md b/plugins/catalog-backend-module-incremental-ingestion/report-alpha.api.md index cb1bb63d00..30717e8752 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/report-alpha.api.md +++ b/plugins/catalog-backend-module-incremental-ingestion/report-alpha.api.md @@ -5,7 +5,7 @@ ```ts import { BackendFeature } from '@backstage/backend-plugin-api'; -// @alpha (undocumented) +// @alpha @deprecated (undocumented) const _feature: BackendFeature; export default _feature; diff --git a/plugins/catalog-backend-module-incremental-ingestion/report.api.md b/plugins/catalog-backend-module-incremental-ingestion/report.api.md index 30ad70164f..b4979b1e37 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/report.api.md +++ b/plugins/catalog-backend-module-incremental-ingestion/report.api.md @@ -7,7 +7,7 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { CatalogBuilder } from '@backstage/plugin-catalog-backend'; -import type { Config } from '@backstage/config'; +import { DatabaseService } from '@backstage/backend-plugin-api'; import type { DeferredEntity } from '@backstage/plugin-catalog-node'; import { EventParams } from '@backstage/plugin-events-node'; import { EventSubscriber } from '@backstage/plugin-events-node'; @@ -15,9 +15,9 @@ import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { HumanDuration } from '@backstage/types'; import { IncrementalEntityProvider as IncrementalEntityProvider_2 } from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; import { IncrementalEntityProviderOptions as IncrementalEntityProviderOptions_2 } from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; -import type { Logger } from 'winston'; -import type { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import type { PluginDatabaseManager } from '@backstage/backend-common'; +import { PermissionsService } from '@backstage/backend-plugin-api'; +import { RootConfigService } from '@backstage/backend-plugin-api'; +import { RootLoggerService } from '@backstage/backend-plugin-api'; import { Router } from 'express'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -39,7 +39,7 @@ export type EntityIteratorResult = cursor?: T; }; -// @public (undocumented) +// @public @deprecated (undocumented) export class IncrementalCatalogBuilder { // (undocumented) addIncrementalEntityProvider( @@ -106,11 +106,11 @@ export const incrementalIngestionProvidersExtensionPoint: ExtensionPoint { client, scheduler: scheduler as Partial as SchedulerService, applyDatabaseMigrations, + events: mockServices.events.mock(), }); const wrapped1 = providers.wrap(provider1, { burstInterval: { seconds: 1 }, diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.ts index c322d9adda..2f8a8df3ba 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/WrapperProviders.ts @@ -36,6 +36,7 @@ import { IncrementalEntityProvider, IncrementalEntityProviderOptions, } from '../types'; +import { EventsService } from '@backstage/plugin-events-node'; /** * Helps in the creation of the catalog entity providers that wrap the @@ -53,6 +54,7 @@ export class WrapperProviders { client: Knex; scheduler: SchedulerService; applyDatabaseMigrations?: typeof applyDatabaseMigrations; + events: EventsService; }, ) {} @@ -73,10 +75,11 @@ export class WrapperProviders { }; } - async adminRouter(): Promise { - return await new IncrementalProviderRouter( + adminRouter(): express.Router { + return new IncrementalProviderRouter( new IncrementalIngestionDatabaseManager({ client: this.options.client }), this.options.logger, + this.options.config, ).createRouter(); } @@ -117,12 +120,17 @@ export class WrapperProviders { connection, }); - const frequency = Duration.isDuration(burstInterval) + let frequency = Duration.isDuration(burstInterval) ? burstInterval : Duration.fromObject(burstInterval); - const length = Duration.isDuration(burstLength) + if (frequency.as('milliseconds') < 5000) { + frequency = Duration.fromObject({ seconds: 5 }); // don't let it be silly low, to not overload the scheduler + } + + let length = Duration.isDuration(burstLength) ? burstLength : Duration.fromObject(burstLength); + length = length.plus(Duration.fromObject({ minutes: 1 })); // some margin from the actual completion await this.options.scheduler.scheduleTask({ id: provider.getProviderName(), @@ -130,6 +138,20 @@ export class WrapperProviders { frequency, timeout: length, }); + + const topics = engine.supportsEventTopics(); + if (topics.length > 0) { + logger.info( + `Provider ${provider.getProviderName()} subscribing to events for topics: ${topics.join( + ',', + )}`, + ); + await this.options.events.subscribe({ + topics, + id: `catalog-backend-module-incremental-ingestion:${provider.getProviderName()}`, + onEvent: evt => engine.onEvent(evt), + }); + } } catch (error) { logger.warn( `Failed to initialize incremental ingestion provider ${provider.getProviderName()}, ${stringifyError( diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts index 8752bd3137..9e931c11fd 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.ts @@ -25,6 +25,7 @@ import { IncrementalEntityProviderOptions, } from '@backstage/plugin-catalog-backend-module-incremental-ingestion'; import { WrapperProviders } from './WrapperProviders'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; /** * @public @@ -106,6 +107,7 @@ export const catalogModuleIncrementalIngestionEntityProvider = httpRouter: coreServices.httpRouter, logger: coreServices.logger, scheduler: coreServices.scheduler, + events: eventsServiceRef, }, async init({ catalog, @@ -114,6 +116,7 @@ export const catalogModuleIncrementalIngestionEntityProvider = httpRouter, logger, scheduler, + events, }) { const client = await database.getClient(); @@ -122,6 +125,7 @@ export const catalogModuleIncrementalIngestionEntityProvider = logger, client, scheduler, + events, }); for (const entry of addedProviders) { @@ -129,7 +133,7 @@ export const catalogModuleIncrementalIngestionEntityProvider = catalog.addEntityProvider(wrapped); } - httpRouter.use(await providers.adminRouter()); + httpRouter.use(providers.adminRouter()); }, }); }, diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/router/routes.ts b/plugins/catalog-backend-module-incremental-ingestion/src/router/routes.ts index d3ccb8863b..ad8d6ce103 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/router/routes.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/router/routes.ts @@ -14,25 +14,29 @@ * limitations under the License. */ -import { errorHandler } from '@backstage/backend-common'; import express from 'express'; import Router from 'express-promise-router'; import { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; +import { Config } from '@backstage/config'; export class IncrementalProviderRouter { private manager: IncrementalIngestionDatabaseManager; private logger: LoggerService; + private config: Config; constructor( manager: IncrementalIngestionDatabaseManager, logger: LoggerService, + config: Config, ) { this.manager = manager; this.logger = logger; + this.config = config; } - async createRouter() { + createRouter(): express.Router { const router = Router(); router.use(express.json()); @@ -249,7 +253,11 @@ export class IncrementalProviderRouter { }, ); - router.use(errorHandler()); + const middleware = MiddlewareFactory.create({ + logger: this.logger, + config: this.config, + }); + router.use(middleware.error()); return router; } diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts deleted file mode 100644 index 89698da1de..0000000000 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2022 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. - */ - -// Think this file will probably go away once we move to backend system -// And restructure into the /dev folder -// eslint-disable-next-line @backstage/no-undeclared-imports -import { createBackend } from '@backstage/backend-defaults'; -import { - coreServices, - createBackendModule, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { ConfigReader } from '@backstage/config'; -import { - IncrementalEntityProvider, - incrementalIngestionProvidersExtensionPoint, -} from '.'; -import catalogModuleIncrementalIngestionEntityProvider from './alpha'; - -const provider: IncrementalEntityProvider = { - getProviderName: () => 'test-provider', - around: burst => burst(0), - next: async (_context, cursor) => { - await new Promise(resolve => setTimeout(resolve, 500)); - if (cursor === undefined || cursor < 3) { - console.log(`### Returning batch #${cursor}`); - return { done: false, entities: [], cursor: (cursor ?? 0) + 1 }; - } - - console.log('### Last batch reached, stopping'); - return { done: true }; - }, -}; - -async function main() { - const config = { - backend: { - baseUrl: 'http://localhost:7007', - listen: ':7007', - database: { client: 'better-sqlite3', connection: ':memory:' }, - }, - }; - - const backend = createBackend(); - - backend.add( - createServiceFactory({ - service: coreServices.rootConfig, - deps: {}, - factory: () => new ConfigReader(config), - }), - ); - backend.add(import('@backstage/plugin-catalog-backend/alpha')); - backend.add(catalogModuleIncrementalIngestionEntityProvider); - backend.add( - createBackendModule({ - pluginId: 'catalog', - moduleId: 'incremental-test-provider', - register(reg) { - reg.registerInit({ - deps: { extension: incrementalIngestionProvidersExtensionPoint }, - async init({ extension }) { - extension.addProvider({ - provider: provider, - options: { - burstInterval: { seconds: 1 }, - burstLength: { seconds: 10 }, - restLength: { seconds: 10 }, - }, - }); - }, - }); - }, - }), - ); - - await backend.start(); -} - -main().catch(error => { - console.error(error.stack); - process.exit(1); -}); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/service/IncrementalCatalogBuilder.ts b/plugins/catalog-backend-module-incremental-ingestion/src/service/IncrementalCatalogBuilder.ts index 04ceef2d26..ed4414b68b 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/service/IncrementalCatalogBuilder.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/service/IncrementalCatalogBuilder.ts @@ -29,7 +29,10 @@ import { IncrementalIngestionDatabaseManager } from '../database/IncrementalInge import { IncrementalProviderRouter } from '../router/routes'; import { EventParams, EventSubscriber } from '@backstage/plugin-events-node'; -/** @public */ +/** + * @public + * @deprecated Please migrate to the new backend system and import `@backstage/plugin-catalog-backend-module-incremental-ingestion` as a module, and add providers to the `incrementalIngestionProvidersExtensionPoint` instead + */ export class IncrementalCatalogBuilder { /** * Creates the incremental catalog builder, which extends the regular catalog builder. @@ -63,6 +66,7 @@ export class IncrementalCatalogBuilder { const incrementalAdminRouter = await new IncrementalProviderRouter( this.manager, routerLogger, + this.env.config, ).createRouter(); return { incrementalAdminRouter }; @@ -97,12 +101,17 @@ export class IncrementalCatalogBuilder { connection, }); - const frequency = Duration.isDuration(burstInterval) + let frequency = Duration.isDuration(burstInterval) ? burstInterval : Duration.fromObject(burstInterval); - const length = Duration.isDuration(burstLength) + if (frequency.as('milliseconds') < 5000) { + frequency = Duration.fromObject({ seconds: 5 }); // don't let it be silly low, to not overload the scheduler + } + + let length = Duration.isDuration(burstLength) ? burstLength : Duration.fromObject(burstLength); + length = length.plus(Duration.fromObject({ minutes: 1 })); // some margin from the actual completion await scheduler.scheduleTask({ id: provider.getProviderName(), diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/types.ts b/plugins/catalog-backend-module-incremental-ingestion/src/types.ts index dd7854b586..2c951aea07 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/types.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/types.ts @@ -14,23 +14,23 @@ * limitations under the License. */ -import type { PluginDatabaseManager } from '@backstage/backend-common'; -import type { Config } from '@backstage/config'; +import { + DatabaseService, + LoggerService, + PermissionsService, + RootConfigService, + RootLoggerService, + SchedulerService, + SchedulerServiceTaskFunction, + UrlReaderService, +} from '@backstage/backend-plugin-api'; import type { DeferredEntity, EntityProviderConnection, } from '@backstage/plugin-catalog-node'; import { EventParams } from '@backstage/plugin-events-node'; -import type { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import type { Logger } from 'winston'; -import { IncrementalIngestionDatabaseManager } from './database/IncrementalIngestionDatabaseManager'; -import { - LoggerService, - UrlReaderService, - SchedulerService, - SchedulerServiceTaskFunction, -} from '@backstage/backend-plugin-api'; import { HumanDuration } from '@backstage/types'; +import { IncrementalIngestionDatabaseManager } from './database/IncrementalIngestionDatabaseManager'; /** * Ingest entities into the catalog in bite-sized chunks. @@ -186,12 +186,12 @@ export interface IncrementalEntityProviderOptions { /** @public */ export type PluginEnvironment = { - logger: Logger; - database: PluginDatabaseManager; + logger: RootLoggerService; + database: DatabaseService; scheduler: SchedulerService; - config: Config; + config: RootConfigService; reader: UrlReaderService; - permissions: PermissionEvaluator; + permissions: PermissionsService; }; export interface IterationEngine { diff --git a/plugins/catalog-backend-module-ldap/CHANGELOG.md b/plugins/catalog-backend-module-ldap/CHANGELOG.md index d8be79ce75..036e3cf152 100644 --- a/plugins/catalog-backend-module-ldap/CHANGELOG.md +++ b/plugins/catalog-backend-module-ldap/CHANGELOG.md @@ -1,5 +1,69 @@ # @backstage/plugin-catalog-backend-module-ldap +## 0.11.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.11.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.11.0-next.0 + +### Minor Changes + +- 732700a: Updated fix for ldap entity mapping which doesn't require extra config setting of dnCaseSensitive +- 95ac4a2: Add new ldap vendor config 'LLDAP' + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.10.0 + +### Minor Changes + +- 415aeb3: Add Support for Google LDAP Vendor + +### Patch Changes + +- 884a86c: Added a `dnCaseSensitive` flag to support LDAP servers with mixed-case attributes. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.10.0-next.2 ### Minor Changes diff --git a/plugins/catalog-backend-module-ldap/package.json b/plugins/catalog-backend-module-ldap/package.json index b2b36df9e2..ac76079370 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.10.0-next.2", + "version": "0.11.0-next.2", "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 12dcffcd02..16546cb773 100644 --- a/plugins/catalog-backend-module-ldap/report.api.md +++ b/plugins/catalog-backend-module-ldap/report.api.md @@ -205,7 +205,6 @@ export type LdapProviderConfig = { export type LdapVendor = { dnAttributeName: string; uuidAttributeName: string; - dnCaseSensitive?: boolean; decodeStringAttribute: (entry: SearchEntry, name: string) => string[]; }; @@ -275,6 +274,5 @@ export type UserTransformer = ( export type VendorConfig = { dnAttributeName?: string; uuidAttributeName?: string; - dnCaseSensitive?: boolean; }; ``` diff --git a/plugins/catalog-backend-module-ldap/src/ldap/client.ts b/plugins/catalog-backend-module-ldap/src/ldap/client.ts index 61dd05f437..ac0be476d5 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/client.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/client.ts @@ -26,6 +26,7 @@ import { ActiveDirectoryVendor, DefaultLdapVendor, GoogleLdapVendor, + LLDAPVendor, FreeIpaVendor, LdapVendor, } from './vendors'; @@ -248,6 +249,8 @@ export class LdapClient { return AEDirVendor; } else if (clientHost === 'ldap.google.com') { return GoogleLdapVendor; + } else if (root && root.raw?.vendorName?.toString() === 'LLDAP') { + return LLDAPVendor; } return DefaultLdapVendor; }) diff --git a/plugins/catalog-backend-module-ldap/src/ldap/config.ts b/plugins/catalog-backend-module-ldap/src/ldap/config.ts index 4b53034d36..6fdf682b42 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/config.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/config.ts @@ -181,13 +181,6 @@ export type VendorConfig = { * Attribute name for the unique identifier (UUID) of an entry, */ uuidAttributeName?: string; - - /** - * Attribute to determine if we need to force the DN and members/memberOf values to be forced to same case. - * Some providers may provide lowercase members but multicase DN names which causes the group filtering to break. - * The default is off, but turning this on forces the inbound DN values and all member values to lowercase. - */ - dnCaseSensitive?: boolean; }; const defaultUserConfig = { @@ -263,7 +256,6 @@ function readVendorConfig( return { dnAttributeName: c.getOptionalString('dnAttributeName'), uuidAttributeName: c.getOptionalString('uuidAttributeName'), - dnCaseSensitive: c.getOptionalBoolean('dnCaseSensitive'), }; } 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 20917a0fcc..007678c188 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.test.ts @@ -333,7 +333,6 @@ describe('readLdapUsers', () => { it('transfers all attributes from for vendorDN case sensitivity', async () => { const vendor = DefaultLdapVendor; - vendor.dnCaseSensitive = true; client.getVendor.mockResolvedValue(vendor); client.searchStreaming.mockImplementation(async (_dn, _opts, fn) => { await fn( @@ -365,15 +364,13 @@ describe('readLdapUsers', () => { }, ]; const { users, userMemberOf } = await readLdapUsers(client, config, vendor); - // reset dnCaseSensitivity - vendor.dnCaseSensitive = false; expect(users).toEqual([ expect.objectContaining({ metadata: { name: 'uid-value', description: 'description-value', annotations: { - [LDAP_DN_ANNOTATION]: 'dn-value', + [LDAP_DN_ANNOTATION]: 'dn-VALUE', [LDAP_RDN_ANNOTATION]: 'uid-value', [LDAP_UUID_ANNOTATION]: 'uuid-value', }, @@ -389,7 +386,7 @@ describe('readLdapUsers', () => { }), ]); expect(userMemberOf).toEqual( - new Map([['dn-value', new Set(['x', 'y', 'z'])]]), + new Map([['dn-VALUE', new Set(['x', 'Y', 'z'])]]), ); }); it('fails to transfer all attributes from for due case sensitivity', async () => { @@ -1111,14 +1108,13 @@ describe('defaultUserTransformerWithCaseSensitiveDNs', () => { }); const vendor = DefaultLdapVendor; - vendor.dnCaseSensitive = true; let output = await defaultUserTransformer(vendor, config, entry); expect(output).toEqual({ apiVersion: 'backstage.io/v1beta1', kind: 'User', metadata: { annotations: { - 'backstage.io/ldap-dn': 'dn-value', + 'backstage.io/ldap-dn': 'dn-VALUE', 'backstage.io/ldap-rdn': 'uid-value', 'backstage.io/ldap-uuid': 'uuid-value', a: 2, @@ -1136,14 +1132,12 @@ describe('defaultUserTransformerWithCaseSensitiveDNs', () => { // exact same inputs again output = await defaultUserTransformer(vendor, config, entry); - // reset dnCaseSensitivity - vendor.dnCaseSensitive = false; expect(output).toEqual({ apiVersion: 'backstage.io/v1beta1', kind: 'User', metadata: { annotations: { - 'backstage.io/ldap-dn': 'dn-value', + 'backstage.io/ldap-dn': 'dn-VALUE', 'backstage.io/ldap-rdn': 'uid-value', 'backstage.io/ldap-uuid': 'uuid-value', a: 2, @@ -1192,7 +1186,6 @@ describe('defaultGroupTransformerWithCaseSensitiveDNs', () => { }); const vendor = DefaultLdapVendor; - vendor.dnCaseSensitive = true; let output = await defaultGroupTransformer(vendor, config, entry); expect(output).toEqual({ @@ -1200,7 +1193,7 @@ describe('defaultGroupTransformerWithCaseSensitiveDNs', () => { kind: 'Group', metadata: { annotations: { - 'backstage.io/ldap-dn': 'dn-value', + 'backstage.io/ldap-dn': 'dn-VALUE', 'backstage.io/ldap-rdn': 'uid-value', 'backstage.io/ldap-uuid': 'uuid-value', a: 2, @@ -1220,14 +1213,12 @@ describe('defaultGroupTransformerWithCaseSensitiveDNs', () => { // exact same inputs again output = await defaultGroupTransformer(vendor, config, entry); - // reset dnCaseSensitivity - vendor.dnCaseSensitive = false; expect(output).toEqual({ apiVersion: 'backstage.io/v1beta1', kind: 'Group', metadata: { annotations: { - 'backstage.io/ldap-dn': 'dn-value', + 'backstage.io/ldap-dn': 'dn-VALUE', 'backstage.io/ldap-rdn': 'uid-value', 'backstage.io/ldap-uuid': 'uuid-value', a: 2, diff --git a/plugins/catalog-backend-module-ldap/src/ldap/read.ts b/plugins/catalog-backend-module-ldap/src/ldap/read.ts index 2ec663d7fe..176d6fca7a 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/read.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/read.ts @@ -80,10 +80,7 @@ export async function defaultUserTransformer( entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v; }); mapStringAttr(entry, vendor, vendor.dnAttributeName, v => { - entity.metadata.annotations![LDAP_DN_ANNOTATION] = getCaseSensitivityValue( - v, - vendor, - ); + entity.metadata.annotations![LDAP_DN_ANNOTATION] = v; }); mapStringAttr(entry, vendor, map.displayName, v => { entity.spec.profile!.displayName = v; @@ -125,8 +122,6 @@ export async function readLdapUsers( vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName, uuidAttributeName: vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName, - dnCaseSensitive: - vendorConfig?.dnCaseSensitive ?? vendorDefaults.dnCaseSensitive, decodeStringAttribute: vendorDefaults.decodeStringAttribute, }; const transformer = opts?.transformer ?? defaultUserTransformer; @@ -195,10 +190,7 @@ export async function defaultGroupTransformer( entity.metadata.annotations![LDAP_UUID_ANNOTATION] = v; }); mapStringAttr(entry, vendor, vendor.dnAttributeName, v => { - entity.metadata.annotations![LDAP_DN_ANNOTATION] = getCaseSensitivityValue( - v, - vendor, - ); + entity.metadata.annotations![LDAP_DN_ANNOTATION] = v; }); mapStringAttr(entry, vendor, map.type, v => { entity.spec.type = v; @@ -248,8 +240,6 @@ export async function readLdapGroups( vendorConfig?.dnAttributeName ?? vendorDefaults.dnAttributeName, uuidAttributeName: vendorConfig?.uuidAttributeName ?? vendorDefaults.uuidAttributeName, - dnCaseSensitive: - vendorConfig?.dnCaseSensitive ?? vendorDefaults.dnCaseSensitive, decodeStringAttribute: vendorDefaults.decodeStringAttribute, }; @@ -351,25 +341,11 @@ function mapReferencesAttr( const values = vendor.decodeStringAttribute(entry, attributeName); const dn = vendor.decodeStringAttribute(entry, vendor.dnAttributeName); if (values && dn && dn.length === 1) { - if (vendor.dnCaseSensitive) { - setter( - dn[0].toLocaleLowerCase('en-US'), - values.map(v => v.toLocaleLowerCase('en-US')), - ); - } else { - setter(dn[0], values); - } + setter(dn[0], values); } } } -/** Validates value exists and if required forced sensitivty value to lowercase */ -function getCaseSensitivityValue(value: string, vendor: LdapVendor) { - return value && vendor.dnCaseSensitive - ? value.toLocaleLowerCase('en-US') - : value; -} - // Inserts a number of values in a key-values mapping function ensureItems( target: Map>, @@ -390,6 +366,20 @@ function ensureItems( } } +/** + * Helper function which dual searches the user/group maps first for original value, then for lowercased value. + * @param map - The map of DN's user or group as the key usually multicased. + * @param searchValue - The DN/memberOf search criteria which could potentially not match the map DN by case. + * @returns The value/result of the search criteria dual searching. + */ +function getValueFromMapWithInsensitiveKey( + map: Map, + searchValue: string, +) { + const result = map.get(searchValue); + return result ? result : map.get(searchValue.toLocaleLowerCase('en-US')); +} + /** * Takes groups and entities with empty relations, and fills in the various * relations that were returned by the readers, and forms the org hierarchy. @@ -420,12 +410,24 @@ export function resolveRelations( for (const user of users) { userMap.set(stringifyEntityRef(user), user); userMap.set(user.metadata.annotations![LDAP_DN_ANNOTATION], user); + userMap.set( + user.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase( + 'en-US', + ), + user, + ); userMap.set(user.metadata.annotations![LDAP_RDN_ANNOTATION], user); userMap.set(user.metadata.annotations![LDAP_UUID_ANNOTATION], user); } for (const group of groups) { groupMap.set(stringifyEntityRef(group), group); groupMap.set(group.metadata.annotations![LDAP_DN_ANNOTATION], group); + groupMap.set( + group.metadata.annotations![LDAP_DN_ANNOTATION]?.toLocaleLowerCase( + 'en-US', + ), + group, + ); groupMap.set(group.metadata.annotations![LDAP_RDN_ANNOTATION], group); groupMap.set(group.metadata.annotations![LDAP_UUID_ANNOTATION], group); } @@ -450,10 +452,10 @@ export function resolveRelations( // express relations in different directions. Some may have a user memberOf // overlay, some don't, for example. for (const [userN, groupsN] of userMemberOf.entries()) { - const user = userMap.get(userN); + const user = getValueFromMapWithInsensitiveKey(userMap, userN); if (user) { for (const groupN of groupsN) { - const group = groupMap.get(groupN); + const group = getValueFromMapWithInsensitiveKey(groupMap, groupN); if (group) { ensureItems(newUserMemberOf, stringifyEntityRef(user), [ stringifyEntityRef(group), @@ -463,10 +465,13 @@ export function resolveRelations( } } for (const [groupN, parentsN] of groupMemberOf.entries()) { - const group = groupMap.get(groupN); + const group = getValueFromMapWithInsensitiveKey(groupMap, groupN); if (group) { for (const parentN of parentsN) { - const parentGroup = groupMap.get(parentN); + const parentGroup = getValueFromMapWithInsensitiveKey( + groupMap, + parentN, + ); if (parentGroup) { ensureItems(newGroupParents, stringifyEntityRef(group), [ stringifyEntityRef(parentGroup), @@ -479,18 +484,21 @@ export function resolveRelations( } } for (const [groupN, membersN] of groupMember.entries()) { - const group = groupMap.get(groupN); + const group = getValueFromMapWithInsensitiveKey(groupMap, groupN); if (group) { for (const memberN of membersN) { // Group members can be both users and groups in the input model, so // try both - const memberUser = userMap.get(memberN); + const memberUser = getValueFromMapWithInsensitiveKey(userMap, memberN); if (memberUser) { ensureItems(newUserMemberOf, stringifyEntityRef(memberUser), [ stringifyEntityRef(group), ]); } else { - const memberGroup = groupMap.get(memberN); + const memberGroup = getValueFromMapWithInsensitiveKey( + groupMap, + memberN, + ); if (memberGroup) { ensureItems(newGroupChildren, stringifyEntityRef(group), [ stringifyEntityRef(memberGroup), @@ -506,21 +514,21 @@ export function resolveRelations( // Write down the relations again into the actual entities for (const [userN, groupsN] of newUserMemberOf.entries()) { - const user = userMap.get(userN); + const user = getValueFromMapWithInsensitiveKey(userMap, userN); if (user) { user.spec.memberOf = Array.from(groupsN).sort(); } } for (const [groupN, parentsN] of newGroupParents.entries()) { if (parentsN.size === 1) { - const group = groupMap.get(groupN); + const group = getValueFromMapWithInsensitiveKey(groupMap, groupN); if (group) { group.spec.parent = parentsN.values().next().value; } } } for (const [groupN, childrenN] of newGroupChildren.entries()) { - const group = groupMap.get(groupN); + const group = getValueFromMapWithInsensitiveKey(groupMap, groupN); if (group) { group.spec.children = Array.from(childrenN).sort(); } diff --git a/plugins/catalog-backend-module-ldap/src/ldap/vendors.ts b/plugins/catalog-backend-module-ldap/src/ldap/vendors.ts index eac8481c3e..872941608d 100644 --- a/plugins/catalog-backend-module-ldap/src/ldap/vendors.ts +++ b/plugins/catalog-backend-module-ldap/src/ldap/vendors.ts @@ -31,11 +31,6 @@ export type LdapVendor = { */ uuidAttributeName: string; - /** - * The attribute that determines behaviour of the (dn,members,memberOf) for entries. - */ - dnCaseSensitive?: boolean; - /** * Decode ldap entry values for a given attribute name to their string representation. * @@ -99,6 +94,16 @@ export const GoogleLdapVendor: LdapVendor = { }, }; +export const LLDAPVendor: LdapVendor = { + dnAttributeName: 'dn', + uuidAttributeName: 'entryuuid', + decodeStringAttribute: (entry, name) => { + return decode(entry, name.toLocaleLowerCase('en-US'), value => { + return value.toString(); + }); + }, +}; + // Decode an attribute to a consumer function decode( entry: SearchEntry, diff --git a/plugins/catalog-backend-module-logs/CHANGELOG.md b/plugins/catalog-backend-module-logs/CHANGELOG.md index 87c194de48..213d04dd40 100644 --- a/plugins/catalog-backend-module-logs/CHANGELOG.md +++ b/plugins/catalog-backend-module-logs/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-catalog-backend-module-logs +## 0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.1.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## 0.1.4 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/backend-plugin-api@1.0.2 + ## 0.1.4-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-logs/package.json b/plugins/catalog-backend-module-logs/package.json index f8d185ead2..402b6b3e8f 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.4-next.3", + "version": "0.1.5-next.2", "description": "A module that subscribes to catalog releated 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 1dfe8417a5..93f8b70860 100644 --- a/plugins/catalog-backend-module-msgraph/CHANGELOG.md +++ b/plugins/catalog-backend-module-msgraph/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-catalog-backend-module-msgraph +## 0.6.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.6.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.6.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.6.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.6.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-msgraph/package.json b/plugins/catalog-backend-module-msgraph/package.json index 0b30e61f8d..8661290585 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.6.4-next.2", + "version": "0.6.5-next.2", "description": "A Backstage catalog backend module that helps integrate towards Microsoft Graph", "backstage": { "role": "backend-plugin-module", @@ -58,9 +58,7 @@ "@backstage/plugin-catalog-common": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", "@microsoft/microsoft-graph-types": "^2.6.0", - "@types/node-fetch": "^2.5.12", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "p-limit": "^3.0.2", "qs": "^6.9.4", "uuid": "^11.0.0" diff --git a/plugins/catalog-backend-module-msgraph/report.api.md b/plugins/catalog-backend-module-msgraph/report.api.md index 35ae148a25..912ca16e85 100644 --- a/plugins/catalog-backend-module-msgraph/report.api.md +++ b/plugins/catalog-backend-module-msgraph/report.api.md @@ -17,7 +17,6 @@ import { LoggerService } from '@backstage/backend-plugin-api'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; import { OrganizationTransformer as OrganizationTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; import { ProviderConfigTransformer as ProviderConfigTransformer_2 } from '@backstage/plugin-catalog-backend-module-msgraph'; -import { Response as Response_2 } from 'node-fetch'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { SchedulerServiceTaskRunner } from '@backstage/backend-plugin-api'; import { SchedulerServiceTaskScheduleDefinition } from '@backstage/backend-plugin-api'; @@ -114,7 +113,7 @@ export class MicrosoftGraphClient { path: string, query?: ODataQuery, headers?: Record, - ): Promise; + ): Promise; requestCollection( path: string, query?: ODataQuery, @@ -124,7 +123,7 @@ export class MicrosoftGraphClient { url: string, headers?: Record, retryCount?: number, - ): Promise; + ): Promise; } // @public diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts index 2dc2a65135..aa2d735a07 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/client.ts @@ -20,7 +20,6 @@ import { ClientSecretCredential, } from '@azure/identity'; import * as MicrosoftGraph from '@microsoft/microsoft-graph-types'; -import fetch, { Response } from 'node-fetch'; import qs from 'qs'; import { MicrosoftGraphProviderConfig } from './config'; diff --git a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts index 60e5c3d79b..4f1c9efbe2 100644 --- a/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts +++ b/plugins/catalog-backend-module-msgraph/src/microsoftGraph/read.ts @@ -296,7 +296,7 @@ export function resolveRelations( groupMember: Map>, groupMemberOf: Map>, ) { - // Build reference lookup tables, we reference them by the id the the graph + // Build reference lookup tables, we reference them by the id of the graph const groupMap: Map = new Map(); // by group-id or tenant-id for (const group of groups) { diff --git a/plugins/catalog-backend-module-openapi/CHANGELOG.md b/plugins/catalog-backend-module-openapi/CHANGELOG.md index 74e38f9db9..72e969e708 100644 --- a/plugins/catalog-backend-module-openapi/CHANGELOG.md +++ b/plugins/catalog-backend-module-openapi/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-catalog-backend-module-openapi +## 0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.2.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-backend@1.29.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-catalog-backend@1.28.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.4 + +### Patch Changes + +- 5f058e2: Updated dependency `@apidevtools/json-schema-ref-parser` to `^11.0.0`. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-backend@1.28.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.2.4-next.3 ### Patch Changes diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index 718c231561..8f7fae6f1e 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.4-next.3", + "version": "0.2.5-next.2", "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 aca25d93d2..9034f0fda9 100644 --- a/plugins/catalog-backend-module-puppetdb/CHANGELOG.md +++ b/plugins/catalog-backend-module-puppetdb/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-catalog-backend-module-puppetdb +## 0.2.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.2.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.2.5-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.4 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.2.4-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-puppetdb/package.json b/plugins/catalog-backend-module-puppetdb/package.json index a8116bb371..80cc2af988 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.4-next.2", + "version": "0.2.5-next.2", "description": "A Backstage catalog backend module that helps integrate towards PuppetDB", "backstage": { "role": "backend-plugin-module", @@ -61,7 +61,6 @@ "@backstage/types": "workspace:^", "lodash": "^4.17.21", "luxon": "^3.0.0", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts b/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts index 18a6eb077f..891b19691a 100644 --- a/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts +++ b/plugins/catalog-backend-module-puppetdb/src/puppet/read.ts @@ -18,7 +18,6 @@ import { PuppetDbEntityProviderConfig } from '../providers'; import { PuppetNode, ResourceTransformer } from './types'; import { ResourceEntity } from '@backstage/catalog-model'; import { defaultResourceTransformer } from './transformers'; -import fetch from 'node-fetch'; import { ResponseError } from '@backstage/errors'; import { ENDPOINT_FACTSETS } from './constants'; import { LoggerService } from '@backstage/backend-plugin-api'; diff --git a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md index 46151a0fa6..0bec90e9db 100644 --- a/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md +++ b/plugins/catalog-backend-module-scaffolder-entity-model/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-catalog-backend-module-scaffolder-entity-model +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.2.2-next.3 ### 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 301e70c525..8aa73ba42b 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.2-next.3", + "version": "0.2.3-next.2", "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 bcfe8fcf6f..8dd8ca1c2f 100644 --- a/plugins/catalog-backend-module-unprocessed/CHANGELOG.md +++ b/plugins/catalog-backend-module-unprocessed/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-catalog-backend-module-unprocessed +## 0.5.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.6-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.5.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + - @backstage/plugin-permission-common@0.8.2 + +## 0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + - @backstage/plugin-permission-common@0.8.2 + +## 0.5.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-unprocessed-entities-common@0.0.5 + ## 0.5.2-next.2 ### Patch Changes diff --git a/plugins/catalog-backend-module-unprocessed/package.json b/plugins/catalog-backend-module-unprocessed/package.json index f9b0543d8d..42685e45a0 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.5.2-next.2", + "version": "0.5.3-next.2", "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 297529527f..65abfa1a07 100644 --- a/plugins/catalog-backend/CHANGELOG.md +++ b/plugins/catalog-backend/CHANGELOG.md @@ -1,5 +1,128 @@ # @backstage/plugin-catalog-backend +## 1.29.0-next.2 + +### Minor Changes + +- c1307b4: Implement `/entities` in terms of `queryEntities` to not run into memory and performance problems on large catalogs + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 8013c9c: Perform the by-query count inlined with the main query +- feba9ee: Use a join based strategy for filtering, when having small page sizes +- 1fdb48e: Use a faster count method on pg when computing some metrics +- 0c33465: Implement `/entities/by-name/:kind/:namespace/:name` using `getEntitiesByRefs` +- d93390d: When parsing filters, do not make redundant `anyOf` and `allOf` nodes when there's only a single entry within them +- 24ecea8: Avoid extra ordering in by-query when the user doesn't ask for it +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.29.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. +- 1d0bc11: Fetch all facets in a single database query + +### Patch Changes + +- e4aab10: Fix a bug where sometimes the `by-query` endpoint could return nulls for entities that were not yet stitched. +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## 1.28.1-next.0 + +### Patch Changes + +- f159b25: Compute deltas more efficiently, which generally leads to less wasted processing cycles +- 56511ba: Be more aggressive in dequeueing entities for stitching +- 71152e3: Correctly report stitching queue length +- 3ab57c6: Support changing location keys on existing entities, in delta mutations +- 2924ffe: Compute some metrics using search table facet aggregations instead of reading the full refresh state +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-search-backend-module-catalog@0.2.6-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 1.28.0 + +### Minor Changes + +- 39fd704: Internal update to use the new generated server types from `backstage-cli package schema openapi generate --server`. +- 76857da: Added `entity_ref` column to `final_entities` in order to move `refresh_state` away from the read path +- 34d4360: Drop redundant indices from the database. + + The following redundant indices are removed in this version: + + - `final_entities_entity_id_idx` - overlaps with `final_entities_pkey` + - `refresh_state_entity_id_idx` - overlaps with `refresh_state_pkey` + - `refresh_state_entity_ref_idx` - overlaps with `refresh_state_entity_ref_uniq` + - `search_key_idx` and `search_value_idx` - these were replaced by the composite index `search_key_value_idx` in #22594 + + No negative end user impact is expected, but rather that performance should increase due to less index churn. + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- b89834b: Fixed an issue where entities would not be marked for restitching if only the target of a relationship changed. +- 1bf02cc: Fixed bug when searching an entity by `spec.profile.displayName` in the catalog on the frontend. Text filter fields were not applied correctly to the database query resulting in empty results. +- 4e58bc7: Upgrade to uuid v11 internally +- 5efde17: Internal refactor to slightly speed up the processing loop +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/plugin-search-backend-module-catalog@0.2.5 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-node@0.8.5 + ## 1.28.0-next.3 ### Minor Changes diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts index 1ab107ef10..384765f92e 100644 --- a/plugins/catalog-backend/config.d.ts +++ b/plugins/catalog-backend/config.d.ts @@ -138,6 +138,16 @@ export interface Config { }>; }>; + /** + * Disables the compatibility layer for relations in returned entities that + * ensures that all relations objects have both `target` and `targetRef`. + * + * Enabling this option significantly reduces the memory usage of the + * catalog, and slightly increases performance, but may break consumers that + * rely on the existence of `target` in the relations objects. + */ + disableRelationsCompatibility?: boolean; + /** * The strategy to use for entities that are orphaned, i.e. no longer have * any other entities or providers referencing them. The default value is @@ -157,9 +167,9 @@ export interface Config { /** Defer stitching to be performed asynchronously */ mode: 'deferred'; /** Polling interval for tasks in seconds */ - pollingInterval?: HumanDuration; + pollingInterval?: HumanDuration | string; /** How long to wait for a stitch to complete before giving up in seconds */ - stitchTimeout?: HumanDuration; + stitchTimeout?: HumanDuration | string; }; /** diff --git a/plugins/catalog-backend/package.json b/plugins/catalog-backend/package.json index 8e73350d24..09c6afd454 100644 --- a/plugins/catalog-backend/package.json +++ b/plugins/catalog-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-backend", - "version": "1.28.0-next.3", + "version": "1.29.0-next.2", "description": "The Backstage backend plugin that provides the Backstage catalog", "backstage": { "role": "backend-plugin", @@ -76,7 +76,7 @@ "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-search-backend-module-catalog": "workspace:^", "@backstage/types": "workspace:^", - "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api": "^1.9.0", "@types/express": "^4.17.6", "codeowners-utils": "^1.0.2", "core-js": "^3.6.5", @@ -89,7 +89,6 @@ "lodash": "^4.17.21", "luxon": "^3.0.0", "minimatch": "^9.0.0", - "node-fetch": "^2.7.0", "p-limit": "^3.0.2", "prom-client": "^15.0.0", "uuid": "^11.0.0", diff --git a/plugins/catalog-backend/src/catalog/types.ts b/plugins/catalog-backend/src/catalog/types.ts index a02c74c0c1..1fbf337986 100644 --- a/plugins/catalog-backend/src/catalog/types.ts +++ b/plugins/catalog-backend/src/catalog/types.ts @@ -52,8 +52,22 @@ export type EntitiesRequest = { credentials: BackstageCredentials; }; +/** + * Encapsulates either a deserialized or serialized entities to be sent in a response. + * @internal + */ +export type EntitiesResponseItems = + | { + type: 'object'; + entities: (Entity | null)[]; + } + | { + type: 'raw'; + entities: (string | null)[]; + }; + export type EntitiesResponse = { - entities: Entity[]; + entities: EntitiesResponseItems; pageInfo: PageInfo; }; @@ -86,7 +100,7 @@ export interface EntitiesBatchResponse { * The list of entities, in the same order as the refs in the request. Entries * that are null signify that no entity existed with that ref. */ - items: Array; + items: EntitiesResponseItems; } export type EntityAncestryResponse = { @@ -203,6 +217,7 @@ export interface QueryEntitiesInitialRequest { term: string; fields?: string[]; }; + skipTotalItems?: boolean; } /** @@ -223,7 +238,7 @@ export interface QueryEntitiesResponse { /** * The entities for the current pagination request */ - items: Entity[]; + items: EntitiesResponseItems; pageInfo: { /** diff --git a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts index 37608b1493..e530c30d8b 100644 --- a/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProcessingDatabase.test.ts @@ -283,7 +283,7 @@ describe('DefaultProcessingDatabase', () => { ); it.each(databases.eachSupportedId())( - 'adds deferred entities to the the refresh_state table to be picked up later, %p', + 'adds deferred entities to the refresh_state table to be picked up later, %p', async databaseId => { const { knex, db } = await createDatabase(databaseId); await insertRefreshStateRow(knex, { diff --git a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts index 0218d25a18..ac361795e1 100644 --- a/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts +++ b/plugins/catalog-backend/src/database/DefaultProviderDatabase.test.ts @@ -19,13 +19,14 @@ import { TestDatabaseId, TestDatabases, } from '@backstage/backend-test-utils'; -import { Entity } from '@backstage/catalog-model'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; import { Knex } from 'knex'; import * as uuid from 'uuid'; import { DefaultProviderDatabase } from './DefaultProviderDatabase'; import { applyDatabaseMigrations } from './migrations'; import { DbRefreshStateReferencesRow, DbRefreshStateRow } from './tables'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { generateStableHash } from './util'; jest.setTimeout(60_000); @@ -690,13 +691,8 @@ describe('DefaultProviderDatabase', () => { it.each(databases.eachSupportedId())( 'should successfully fall back from batch to individual mode on conflicts, %p', async databaseId => { - const fakeLogger = { - debug: jest.fn(), - }; - const { knex, db } = await createDatabase( - databaseId, - fakeLogger as any, - ); + const fakeLogger = mockServices.logger.mock(); + const { knex, db } = await createDatabase(databaseId, fakeLogger); await createLocations(knex, ['component:default/a']); @@ -744,11 +740,8 @@ describe('DefaultProviderDatabase', () => { it.each(databases.eachSupportedId())( 'should gracefully handle accidental duplicate refresh state references when deletion happens during a full sync, %p', async databaseId => { - const fakeLogger = { debug: jest.fn() }; - const { knex, db } = await createDatabase( - databaseId, - fakeLogger as any, - ); + const fakeLogger = mockServices.logger.mock(); + const { knex, db } = await createDatabase(databaseId, fakeLogger); await createLocations(knex, ['component:default/a']); @@ -773,5 +766,226 @@ describe('DefaultProviderDatabase', () => { expect(state).toEqual([]); }, ); + + it.each(databases.eachSupportedId())( + 'should properly translate deltas into add/update/remove, %p', + async databaseId => { + const fakeLogger = mockServices.logger.mock(); + const { knex, db } = await createDatabase(databaseId, fakeLogger); + + const entity1Before: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n1' }, + }; + const entity1After: Entity = { + ...entity1Before, + apiVersion: '2', + }; + + const entity2Before: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n2' }, + }; + const entity2After: Entity = { + ...entity2Before, + apiVersion: '2', + }; + + const entity3: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n3' }, + }; + + const entity4: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n4' }, + }; + + const entity5: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n5' }, + }; + + const entity6: Entity = { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: 'n6' }, + }; + + await insertRefreshStateRow(knex, { + entity_id: 'id1', + entity_ref: stringifyEntityRef(entity1Before), + last_discovery_at: new Date(), + next_update_at: new Date(), + errors: '[]', + unprocessed_entity: JSON.stringify(entity1Before), + unprocessed_hash: generateStableHash(entity1Before), + }); + await insertRefRow(knex, { + source_key: 'my-provider', + target_entity_ref: stringifyEntityRef(entity1Before), + }); + await insertRefreshStateRow(knex, { + entity_id: 'id2', + entity_ref: stringifyEntityRef(entity2Before), + last_discovery_at: new Date(), + next_update_at: new Date(), + errors: '[]', + unprocessed_entity: JSON.stringify(entity2Before), + unprocessed_hash: generateStableHash(entity2After), // lie about the hash! + }); + await insertRefRow(knex, { + source_key: 'my-provider', + target_entity_ref: stringifyEntityRef(entity2Before), + }); + await insertRefreshStateRow(knex, { + entity_id: 'id4', + entity_ref: stringifyEntityRef(entity4), + last_discovery_at: new Date(), + next_update_at: new Date(), + errors: '[]', + unprocessed_entity: JSON.stringify(entity4), + unprocessed_hash: generateStableHash(entity4), + }); + await insertRefRow(knex, { + source_key: 'my-provider', + target_entity_ref: stringifyEntityRef(entity4), + }); + await insertRefreshStateRow(knex, { + entity_id: 'id5', + entity_ref: stringifyEntityRef(entity5), + last_discovery_at: new Date(), + next_update_at: new Date(), + errors: '[]', + unprocessed_entity: JSON.stringify(entity5), + unprocessed_hash: generateStableHash(entity5), + }); + await insertRefRow(knex, { + source_key: 'my-provider', + target_entity_ref: stringifyEntityRef(entity5), + }); + await insertRefreshStateRow(knex, { + entity_id: 'id6', + entity_ref: stringifyEntityRef(entity6), + last_discovery_at: new Date(), + next_update_at: new Date(), + errors: '[]', + unprocessed_entity: JSON.stringify(entity6), + unprocessed_hash: generateStableHash(entity6), + location_key: 'old', + }); + await insertRefRow(knex, { + source_key: 'my-provider', + target_entity_ref: stringifyEntityRef(entity6), + }); + + await db.transaction(async tx => { + await db.replaceUnprocessedEntities(tx, { + type: 'delta', + sourceKey: 'my-provider', + added: [ + // we used the right hashes for entity1, so this will turn into an update + { entity: entity1After }, + // we lied about the hash for entity2, so this will become a no-op + { entity: entity2After }, + // this didn't exist, so will become an add + { entity: entity3 }, + // only the location key changed, so this will become an update + { entity: entity5, locationKey: 'new' }, + // only the location key changed, so this will become an update + { entity: entity6, locationKey: 'new' }, + ], + removed: [{ entityRef: stringifyEntityRef(entity4) }], + }); + }); + + const state = await knex('refresh_state') + .select([ + 'entity_ref', + 'unprocessed_entity', + 'unprocessed_hash', + 'location_key', + ]) + .orderBy('entity_ref'); + + expect(state).toEqual([ + { + entity_ref: stringifyEntityRef(entity1After), + unprocessed_entity: JSON.stringify(entity1After), + unprocessed_hash: generateStableHash(entity1After), + location_key: null, + }, + { + entity_ref: stringifyEntityRef(entity2After), + unprocessed_entity: JSON.stringify(entity2Before), // didn't change + unprocessed_hash: generateStableHash(entity2After), + location_key: null, + }, + { + entity_ref: stringifyEntityRef(entity3), + unprocessed_entity: JSON.stringify(entity3), + unprocessed_hash: generateStableHash(entity3), + location_key: null, + }, + // entity4 was deleted here + { + entity_ref: stringifyEntityRef(entity5), + unprocessed_entity: JSON.stringify(entity5), + unprocessed_hash: generateStableHash(entity5), + location_key: 'new', // permitted to change, because it was null before + }, + { + entity_ref: stringifyEntityRef(entity6), + unprocessed_entity: JSON.stringify(entity6), + unprocessed_hash: generateStableHash(entity6), + location_key: 'new', // managed to update only the location key + }, + ]); + }, + ); + + it.each(databases.eachSupportedId())( + 'can handle large deltas without exploding, %p', + async databaseId => { + const fakeLogger = mockServices.logger.mock(); + const { knex, db } = await createDatabase(databaseId, fakeLogger); + + const count = 10000; + const padded = (n: number) => String(n).padStart(8, '0'); + + const entities = Array.from({ length: count }, (_, i) => ({ + entity: { + apiVersion: '1', + kind: 'k', + metadata: { namespace: 'ns', name: padded(i) }, + }, + })); + + await db.transaction(async tx => { + await db.replaceUnprocessedEntities(tx, { + type: 'delta', + sourceKey: 'my-provider', + added: entities, + removed: [], + }); + }); + + const state = await knex('refresh_state') + .select(['entity_ref', 'unprocessed_entity', 'unprocessed_hash']) + .orderBy('entity_ref'); + + expect(state).toHaveLength(count); + expect(state[0]).toEqual({ + entity_ref: stringifyEntityRef(entities[0].entity), + unprocessed_entity: JSON.stringify(entities[0].entity), + unprocessed_hash: generateStableHash(entities[0].entity), + }); + }, + ); }); }); diff --git a/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts b/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts index 94026fbfa0..03f72e06b7 100644 --- a/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts +++ b/plugins/catalog-backend/src/database/DefaultProviderDatabase.ts @@ -75,10 +75,10 @@ export class DefaultProviderDatabase implements ProviderDatabase { } async replaceUnprocessedEntities( - txOpaque: Transaction, + txOpaque: Knex | Transaction, options: ReplaceUnprocessedEntitiesOptions, ): Promise { - const tx = txOpaque as Knex.Transaction; + const tx = txOpaque as Knex | Knex.Transaction; const { toAdd, toUpsert, toRemove } = await this.createDelta(tx, options); if (toRemove.length) { @@ -205,7 +205,7 @@ export class DefaultProviderDatabase implements ProviderDatabase { } private async createDelta( - tx: Knex.Transaction, + tx: Knex | Knex.Transaction, options: ReplaceUnprocessedEntitiesOptions, ): Promise<{ toAdd: { deferred: DeferredEntity; hash: string }[]; @@ -213,14 +213,46 @@ export class DefaultProviderDatabase implements ProviderDatabase { toRemove: string[]; }> { if (options.type === 'delta') { - return { - toAdd: [], - toUpsert: options.added.map(e => ({ - deferred: e, - hash: generateStableHash(e.entity), - })), - toRemove: options.removed.map(e => e.entityRef), - }; + const toAdd = new Array<{ deferred: DeferredEntity; hash: string }>(); + const toUpsert = new Array<{ deferred: DeferredEntity; hash: string }>(); + const toRemove = options.removed.map(e => e.entityRef); + + for (const chunk of lodash.chunk(options.added, 1000)) { + const entityRefs = chunk.map(e => stringifyEntityRef(e.entity)); + const rows = await tx('refresh_state') + .select(['entity_ref', 'unprocessed_hash', 'location_key']) + .whereIn('entity_ref', entityRefs); + const oldStates = new Map( + rows.map(row => [ + row.entity_ref, + { + unprocessed_hash: row.unprocessed_hash, + location_key: row.location_key, + }, + ]), + ); + + chunk.forEach((deferred, i) => { + const entityRef = entityRefs[i]; + const newHash = generateStableHash(deferred.entity); + const oldState = oldStates.get(entityRef); + if (oldState === undefined) { + // Add any entity that does not exist in the database + toAdd.push({ deferred, hash: newHash }); + } else if ( + (deferred.locationKey ?? null) !== (oldState.location_key ?? null) + ) { + // Remove and then re-add any entity that exists, but with a different location key + toRemove.push(entityRef); + toAdd.push({ deferred, hash: newHash }); + } else if (newHash !== oldState.unprocessed_hash) { + // Entities with modifications should be pushed through too + toUpsert.push({ deferred, hash: newHash }); + } + }); + } + + return { toAdd, toUpsert, toRemove }; } // Grab all of the existing references from the same source, and their locationKeys as well @@ -267,7 +299,7 @@ export class DefaultProviderDatabase implements ProviderDatabase { // Add any entity that does not exist in the database toAdd.push(upsertItem); } else if ( - (oldRef?.locationKey ?? undefined) !== + (oldRef.locationKey ?? undefined) !== (item.deferred.locationKey ?? undefined) ) { // Remove and then re-add any entity that exists, but with a different location key diff --git a/plugins/catalog-backend/src/database/metrics.ts b/plugins/catalog-backend/src/database/metrics.ts index 8eb307ea46..809405d69f 100644 --- a/plugins/catalog-backend/src/database/metrics.ts +++ b/plugins/catalog-backend/src/database/metrics.ts @@ -16,9 +16,8 @@ import { Knex } from 'knex'; import { createGaugeMetric } from '../util/metrics'; -import { DbRefreshStateRow, DbRelationsRow, DbLocationsRow } from './tables'; +import { DbRelationsRow, DbLocationsRow, DbSearchRow } from './tables'; import { metrics } from '@opentelemetry/api'; -import { parseEntityRef } from '@backstage/catalog-model'; export function initDatabaseMetrics(knex: Knex) { const seenProm = new Set(); @@ -30,23 +29,22 @@ export function initDatabaseMetrics(knex: Knex) { help: 'Total amount of entities in the catalog. DEPRECATED: Please use opentelemetry metrics instead.', labelNames: ['kind'], async collect() { - const result = await knex('refresh_state').select( - 'entity_ref', - ); - const results = result - .map(row => row.entity_ref.split(':')[0]) - .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map()); + const results = await knex('search') + .where('key', '=', 'kind') + .whereNotNull('value') + .select({ kind: 'value', count: knex.raw('count(*)') }) + .groupBy('value'); - results.forEach((value, key) => { - seenProm.add(key); - this.set({ kind: key }, value); + results.forEach(({ kind, count }) => { + seenProm.add(kind); + this.set({ kind }, Number(count)); }); // Set all the entities that were not seenProm to 0 and delete them from the seenProm set. - seenProm.forEach(key => { - if (!results.has(key)) { - this.set({ kind: key }, 0); - seenProm.delete(key); + seenProm.forEach(kind => { + if (!results.some(r => r.kind === kind)) { + this.set({ kind }, 0); + seenProm.delete(kind); } }); }, @@ -76,23 +74,22 @@ export function initDatabaseMetrics(knex: Knex) { description: 'Total amount of entities in the catalog', }) .addCallback(async gauge => { - const result = await knex('refresh_state').select( - 'entity_ref', - ); - const results = result - .map(row => parseEntityRef(row.entity_ref).kind) - .reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map()); + const results = await knex('search') + .where('key', '=', 'kind') + .whereNotNull('value') + .select({ kind: 'value', count: knex.raw('count(*)') }) + .groupBy('value'); - results.forEach((value, key) => { - seen.add(key); - gauge.observe(value, { kind: key }); + results.forEach(({ kind, count }) => { + seen.add(kind); + gauge.observe(Number(count), { kind }); }); // Set all the entities that were not seen to 0 and delete them from the seen set. - seen.forEach(key => { - if (!results.has(key)) { - gauge.observe(0, { kind: key }); - seen.delete(key); + seen.forEach(kind => { + if (!results.some(r => r.kind === kind)) { + gauge.observe(0, { kind }); + seen.delete(kind); } }); }), @@ -101,20 +98,40 @@ export function initDatabaseMetrics(knex: Knex) { description: 'Total amount of registered locations in the catalog', }) .addCallback(async gauge => { - const total = await knex('locations').count({ - count: '*', - }); - gauge.observe(Number(total[0].count)); + if (knex.client.config.client === 'pg') { + // https://stackoverflow.com/questions/7943233/fast-way-to-discover-the-row-count-of-a-table-in-postgresql + const total = await knex.raw(` + SELECT reltuples::bigint AS estimate + FROM pg_class + WHERE oid = 'locations'::regclass; + `); + gauge.observe(Number(total.rows[0].estimate)); + } else { + const total = await knex('locations').count({ + count: '*', + }); + gauge.observe(Number(total[0].count)); + } }), relations: meter .createObservableGauge('catalog_relations_count', { description: 'Total amount of relations between entities', }) .addCallback(async gauge => { - const total = await knex('relations').count({ - count: '*', - }); - gauge.observe(Number(total[0].count)); + if (knex.client.config.client === 'pg') { + // https://stackoverflow.com/questions/7943233/fast-way-to-discover-the-row-count-of-a-table-in-postgresql + const total = await knex.raw(` + SELECT reltuples::bigint AS estimate + FROM pg_class + WHERE oid = 'relations'::regclass; + `); + gauge.observe(Number(total.rows[0].estimate)); + } else { + const total = await knex('relations').count({ + count: '*', + }); + gauge.observe(Number(total[0].count)); + } }), }; } diff --git a/plugins/catalog-backend/src/database/operations/refreshState/checkLocationKeyConflict.ts b/plugins/catalog-backend/src/database/operations/refreshState/checkLocationKeyConflict.ts index 97d376f9a4..cf6c920d1d 100644 --- a/plugins/catalog-backend/src/database/operations/refreshState/checkLocationKeyConflict.ts +++ b/plugins/catalog-backend/src/database/operations/refreshState/checkLocationKeyConflict.ts @@ -24,7 +24,7 @@ import { DbRefreshStateRow } from '../../tables'; * @returns The conflicting key if there is one. */ export async function checkLocationKeyConflict(options: { - tx: Knex.Transaction; + tx: Knex | Knex.Transaction; entityRef: string; locationKey?: string; }): Promise { diff --git a/plugins/catalog-backend/src/database/operations/refreshState/insertUnprocessedEntity.ts b/plugins/catalog-backend/src/database/operations/refreshState/insertUnprocessedEntity.ts index 195dbe1f2c..54067c3f2e 100644 --- a/plugins/catalog-backend/src/database/operations/refreshState/insertUnprocessedEntity.ts +++ b/plugins/catalog-backend/src/database/operations/refreshState/insertUnprocessedEntity.ts @@ -28,7 +28,7 @@ import { * true if successful and false if there was a conflict. */ export async function insertUnprocessedEntity(options: { - tx: Knex.Transaction; + tx: Knex | Knex.Transaction; entity: Entity; hash: string; locationKey?: string; diff --git a/plugins/catalog-backend/src/database/operations/refreshState/updateUnprocessedEntity.ts b/plugins/catalog-backend/src/database/operations/refreshState/updateUnprocessedEntity.ts index e26db4429b..ced6b0d54d 100644 --- a/plugins/catalog-backend/src/database/operations/refreshState/updateUnprocessedEntity.ts +++ b/plugins/catalog-backend/src/database/operations/refreshState/updateUnprocessedEntity.ts @@ -25,7 +25,7 @@ import { DbRefreshStateRow } from '../../tables'; * Updating the entity will also cause it to be scheduled for immediate processing. */ export async function updateUnprocessedEntity(options: { - tx: Knex.Transaction; + tx: Knex | Knex.Transaction; entity: Entity; hash: string; locationKey?: string; diff --git a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts index 198de7209d..2ed65d3903 100644 --- a/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts +++ b/plugins/catalog-backend/src/database/operations/stitcher/performStitching.ts @@ -55,193 +55,195 @@ export async function performStitching(options: { const { knex, logger, entityRef } = options; const stitchTicket = options.stitchTicket ?? uuid(); - const entityResult = await knex('refresh_state') - .where({ entity_ref: entityRef }) - .limit(1) - .select('entity_id'); - if (!entityResult.length) { - // Entity does no exist in refresh state table, no stitching required. - return 'abandoned'; - } + // In deferred mode, the entity is removed from the stitch queue on ANY + // completion, except when an exception is thrown. In the latter case, the + // entity will be retried at a later time. + let removeFromStitchQueueOnCompletion = options.strategy.mode === 'deferred'; - // Insert stitching ticket that will be compared before inserting the final entity. - await knex('final_entities') - .insert({ - entity_id: entityResult[0].entity_id, - hash: '', - entity_ref: entityRef, - stitch_ticket: stitchTicket, - }) - .onConflict('entity_id') - .merge(['stitch_ticket']); + try { + const entityResult = await knex('refresh_state') + .where({ entity_ref: entityRef }) + .limit(1) + .select('entity_id'); + if (!entityResult.length) { + // Entity does no exist in refresh state table, no stitching required. + return 'abandoned'; + } - // Selecting from refresh_state and final_entities should yield exactly - // one row (except in abnormal cases where the stitch was invoked for - // something that didn't exist at all, in which case it's zero rows). - // The join with the temporary incoming_references still gives one row. - const [processedResult, relationsResult] = await Promise.all([ - knex - .with('incoming_references', function incomingReferences(builder) { - return builder - .from('refresh_state_references') - .where({ target_entity_ref: entityRef }) - .count({ count: '*' }); + // Insert stitching ticket that will be compared before inserting the final entity. + await knex('final_entities') + .insert({ + entity_id: entityResult[0].entity_id, + hash: '', + entity_ref: entityRef, + stitch_ticket: stitchTicket, }) - .select({ - entityId: 'refresh_state.entity_id', - processedEntity: 'refresh_state.processed_entity', - errors: 'refresh_state.errors', - incomingReferenceCount: 'incoming_references.count', - previousHash: 'final_entities.hash', - }) - .from('refresh_state') - .where({ 'refresh_state.entity_ref': entityRef }) - .crossJoin(knex.raw('incoming_references')) - .leftOuterJoin('final_entities', { - 'final_entities.entity_id': 'refresh_state.entity_id', - }), - knex - .distinct({ - relationType: 'type', - relationTarget: 'target_entity_ref', - }) - .from('relations') - .where({ source_entity_ref: entityRef }) - .orderBy('relationType', 'asc') - .orderBy('relationTarget', 'asc'), - ]); + .onConflict('entity_id') + .merge(['stitch_ticket']); - // If there were no rows returned, it would mean that there was no - // matching row even in the refresh_state. This can happen for example - // if we emit a relation to something that hasn't been ingested yet. - // It's safe to ignore this stitch attempt in that case. - if (!processedResult.length) { - logger.debug( - `Unable to stitch ${entityRef}, item does not exist in refresh state table`, - ); - return 'abandoned'; - } + // Selecting from refresh_state and final_entities should yield exactly + // one row (except in abnormal cases where the stitch was invoked for + // something that didn't exist at all, in which case it's zero rows). + // The join with the temporary incoming_references still gives one row. + const [processedResult, relationsResult] = await Promise.all([ + knex + .with('incoming_references', function incomingReferences(builder) { + return builder + .from('refresh_state_references') + .where({ target_entity_ref: entityRef }) + .count({ count: '*' }); + }) + .select({ + entityId: 'refresh_state.entity_id', + processedEntity: 'refresh_state.processed_entity', + errors: 'refresh_state.errors', + incomingReferenceCount: 'incoming_references.count', + previousHash: 'final_entities.hash', + }) + .from('refresh_state') + .where({ 'refresh_state.entity_ref': entityRef }) + .crossJoin(knex.raw('incoming_references')) + .leftOuterJoin('final_entities', { + 'final_entities.entity_id': 'refresh_state.entity_id', + }), + knex + .distinct({ + relationType: 'type', + relationTarget: 'target_entity_ref', + }) + .from('relations') + .where({ source_entity_ref: entityRef }) + .orderBy('relationType', 'asc') + .orderBy('relationTarget', 'asc'), + ]); - const { - entityId, - processedEntity, - errors, - incomingReferenceCount, - previousHash, - } = processedResult[0]; + // If there were no rows returned, it would mean that there was no + // matching row even in the refresh_state. This can happen for example + // if we emit a relation to something that hasn't been ingested yet. + // It's safe to ignore this stitch attempt in that case. + if (!processedResult.length) { + logger.debug( + `Unable to stitch ${entityRef}, item does not exist in refresh state table`, + ); + return 'abandoned'; + } - // If there was no processed entity in place, the target hasn't been - // through the processing steps yet. It's safe to ignore this stitch - // attempt in that case, since another stitch will be triggered when - // that processing has finished. - if (!processedEntity) { - logger.debug( - `Unable to stitch ${entityRef}, the entity has not yet been processed`, - ); - return 'abandoned'; - } + const { + entityId, + processedEntity, + errors, + incomingReferenceCount, + previousHash, + } = processedResult[0]; - // Grab the processed entity and stitch all of the relevant data into - // it - const entity = JSON.parse(processedEntity) as AlphaEntity; - const isOrphan = Number(incomingReferenceCount) === 0; - let statusItems: EntityStatusItem[] = []; + // If there was no processed entity in place, the target hasn't been + // through the processing steps yet. It's safe to ignore this stitch + // attempt in that case, since another stitch will be triggered when + // that processing has finished. + if (!processedEntity) { + logger.debug( + `Unable to stitch ${entityRef}, the entity has not yet been processed`, + ); + return 'abandoned'; + } - if (isOrphan) { - logger.debug(`${entityRef} is an orphan`); - entity.metadata.annotations = { - ...entity.metadata.annotations, - ['backstage.io/orphan']: 'true', - }; - } - if (errors) { - const parsedErrors = JSON.parse(errors) as SerializedError[]; - if (Array.isArray(parsedErrors) && parsedErrors.length) { - statusItems = parsedErrors.map(e => ({ - type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE, - level: 'error', - message: `${e.name}: ${e.message}`, - error: e, + // Grab the processed entity and stitch all of the relevant data into + // it + const entity = JSON.parse(processedEntity) as AlphaEntity; + const isOrphan = Number(incomingReferenceCount) === 0; + let statusItems: EntityStatusItem[] = []; + + if (isOrphan) { + logger.debug(`${entityRef} is an orphan`); + entity.metadata.annotations = { + ...entity.metadata.annotations, + ['backstage.io/orphan']: 'true', + }; + } + if (errors) { + const parsedErrors = JSON.parse(errors) as SerializedError[]; + if (Array.isArray(parsedErrors) && parsedErrors.length) { + statusItems = parsedErrors.map(e => ({ + type: ENTITY_STATUS_CATALOG_PROCESSING_TYPE, + level: 'error', + message: `${e.name}: ${e.message}`, + error: e, + })); + } + } + // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors + for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) { + const value = entity.metadata.annotations?.[annotation]; + if (typeof value === 'string' && scriptProtocolPattern.test(value)) { + entity.metadata.annotations![annotation] = + 'https://backstage.io/annotation-rejected-for-security-reasons'; + } + } + + // TODO: entityRef is lower case and should be uppercase in the final + // result + entity.relations = relationsResult + .filter(row => row.relationType /* exclude null row, if relevant */) + .map(row => ({ + type: row.relationType!, + targetRef: row.relationTarget!, })); + if (statusItems.length) { + entity.status = { + ...entity.status, + items: [...(entity.status?.items ?? []), ...statusItems], + }; } - } - // We opt to do this check here as we otherwise can't guarantee that it will be run after all processors - for (const annotation of [ANNOTATION_VIEW_URL, ANNOTATION_EDIT_URL]) { - const value = entity.metadata.annotations?.[annotation]; - if (typeof value === 'string' && scriptProtocolPattern.test(value)) { - entity.metadata.annotations![annotation] = - 'https://backstage.io/annotation-rejected-for-security-reasons'; + + // If the output entity was actually not changed, just abort + const hash = generateStableHash(entity); + if (hash === previousHash) { + logger.debug(`Skipped stitching of ${entityRef}, no changes`); + return 'unchanged'; } - } - // TODO: entityRef is lower case and should be uppercase in the final - // result - entity.relations = relationsResult - .filter(row => row.relationType /* exclude null row, if relevant */) - .map(row => ({ - type: row.relationType!, - targetRef: row.relationTarget!, - })); - if (statusItems.length) { - entity.status = { - ...entity.status, - items: [...(entity.status?.items ?? []), ...statusItems], - }; - } - - // If the output entity was actually not changed, just abort - const hash = generateStableHash(entity); - if (hash === previousHash) { - logger.debug(`Skipped stitching of ${entityRef}, no changes`); - return 'unchanged'; - } - - entity.metadata.uid = entityId; - if (!entity.metadata.etag) { - // If the original data source did not have its own etag handling, - // use the hash as a good-quality etag - entity.metadata.etag = hash; - } - - // This may throw if the entity is invalid, so we call it before - // the final_entities write, even though we may end up not needing - // to write the search index. - const searchEntries = buildEntitySearch(entityId, entity); - - const amountOfRowsChanged = await knex('final_entities') - .update({ - final_entity: JSON.stringify(entity), - hash, - last_updated_at: knex.fn.now(), - entity_ref: entityRef, - }) - .where('entity_id', entityId) - .where('stitch_ticket', stitchTicket) - .onConflict('entity_id') - .merge(['final_entity', 'hash', 'last_updated_at']); - - const markDeferred = async () => { - if (options.strategy.mode !== 'deferred') { - return; + entity.metadata.uid = entityId; + if (!entity.metadata.etag) { + // If the original data source did not have its own etag handling, + // use the hash as a good-quality etag + entity.metadata.etag = hash; } - await markDeferredStitchCompleted({ - knex: knex, - entityRef, - stitchTicket, + + // This may throw if the entity is invalid, so we call it before + // the final_entities write, even though we may end up not needing + // to write the search index. + const searchEntries = buildEntitySearch(entityId, entity); + + const amountOfRowsChanged = await knex('final_entities') + .update({ + final_entity: JSON.stringify(entity), + hash, + last_updated_at: knex.fn.now(), + }) + .where('entity_id', entityId) + .where('stitch_ticket', stitchTicket); + + if (amountOfRowsChanged === 0) { + logger.debug(`Entity ${entityRef} is already stitched, skipping write.`); + return 'abandoned'; + } + + await knex.transaction(async trx => { + await trx('search').where({ entity_id: entityId }).delete(); + await trx.batchInsert('search', searchEntries, BATCH_SIZE); }); - }; - if (amountOfRowsChanged === 0) { - logger.debug(`Entity ${entityRef} is already stitched, skipping write.`); - await markDeferred(); - return 'abandoned'; + return 'changed'; + } catch (error) { + removeFromStitchQueueOnCompletion = false; + throw error; + } finally { + if (removeFromStitchQueueOnCompletion) { + await markDeferredStitchCompleted({ + knex: knex, + entityRef, + stitchTicket, + }); + } } - - await knex.transaction(async trx => { - await trx('search').where({ entity_id: entityId }).delete(); - await trx.batchInsert('search', searchEntries, BATCH_SIZE); - }); - - await markDeferred(); - return 'changed'; } diff --git a/plugins/catalog-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts b/plugins/catalog-backend/src/schema/openapi/generated/apis/Api.server.ts similarity index 99% rename from plugins/catalog-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts rename to plugins/catalog-backend/src/schema/openapi/generated/apis/Api.server.ts index 8789eee1f6..abd73e2876 100644 --- a/plugins/catalog-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts +++ b/plugins/catalog-backend/src/schema/openapi/generated/apis/Api.server.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// + // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** @@ -190,10 +192,6 @@ export type ValidateEntity = { response: void | ValidateEntity400Response; }; -/** - * no description - */ - export type EndpointMap = { '#post|/analyze-location': AnalyzeLocation; diff --git a/plugins/catalog-backend/src/schema/openapi/generated/apis/index.ts b/plugins/catalog-backend/src/schema/openapi/generated/apis/index.ts index 79855a6fc8..a3cdbbebd2 100644 --- a/plugins/catalog-backend/src/schema/openapi/generated/apis/index.ts +++ b/plugins/catalog-backend/src/schema/openapi/generated/apis/index.ts @@ -14,4 +14,10 @@ * limitations under the License. */ -export * from './DefaultApi.server'; +// + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +export * from './Api.server'; diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts index 3e2dee7ae0..894949a691 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.test.ts @@ -64,7 +64,7 @@ describe('AuthorizedEntitiesCatalog', () => { credentials: mockCredentials.none(), }), ).toEqual({ - entities: [], + entities: { type: 'object', entities: [] }, pageInfo: { hasNextPage: false }, }); }); @@ -113,7 +113,7 @@ describe('AuthorizedEntitiesCatalog', () => { credentials: mockCredentials.none(), }), ).resolves.toEqual({ - items: [null], + items: { type: 'object', entities: [null] }, }); expect(fakeCatalog.entitiesBatch).not.toHaveBeenCalled(); @@ -174,7 +174,7 @@ describe('AuthorizedEntitiesCatalog', () => { filter: { key: 'kind', values: ['b'] }, }), ).resolves.toEqual({ - items: [], + items: { type: 'object', entities: [] }, pageInfo: {}, totalItems: 0, }); @@ -226,7 +226,7 @@ describe('AuthorizedEntitiesCatalog', () => { ]; fakeCatalog.queryEntities.mockResolvedValue({ - items: entities, + items: { type: 'object', entities }, pageInfo: { nextCursor: { isPrevious: false, @@ -254,7 +254,7 @@ describe('AuthorizedEntitiesCatalog', () => { }); expect(response).toEqual({ - items: entities, + items: { type: 'object', entities: entities }, totalItems: 4, pageInfo: { nextCursor: { @@ -290,7 +290,7 @@ describe('AuthorizedEntitiesCatalog', () => { }); expect(response).toEqual({ - items: entities, + items: { type: 'object', entities: entities }, totalItems: 4, pageInfo: { nextCursor: { @@ -338,7 +338,9 @@ describe('AuthorizedEntitiesCatalog', () => { conditions: { rule: 'IS_ENTITY_KIND', params: { kinds: ['b'] } }, }, ]); - fakeCatalog.entities.mockResolvedValue({ entities: [] }); + fakeCatalog.entities.mockResolvedValue({ + entities: { type: 'object', entities: [] }, + }); const catalog = new AuthorizedEntitiesCatalog( fakeCatalog, fakePermissionApi, @@ -360,7 +362,10 @@ describe('AuthorizedEntitiesCatalog', () => { }, ]); fakeCatalog.entities.mockResolvedValue({ - entities: [{ kind: 'b', namespace: 'default', name: 'my-component' }], + entities: { + type: 'object', + entities: [{ kind: 'b', namespace: 'default', name: 'my-component' }], + }, }); const catalog = new AuthorizedEntitiesCatalog( fakeCatalog, diff --git a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts index 5358e90825..073e153dcc 100644 --- a/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/AuthorizedEntitiesCatalog.ts @@ -60,7 +60,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog { if (authorizeDecision.result === AuthorizeResult.DENY) { return { - entities: [], + entities: { type: 'object', entities: [] }, pageInfo: { hasNextPage: false }, }; } @@ -92,7 +92,10 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog { if (authorizeDecision.result === AuthorizeResult.DENY) { return { - items: new Array(request.entityRefs.length).fill(null), + items: { + type: 'object', + entities: new Array(request.entityRefs.length).fill(null), + }, }; } @@ -123,7 +126,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog { if (authorizeDecision.result === AuthorizeResult.DENY) { return { - items: [], + items: { type: 'object', entities: [] }, pageInfo: {}, totalItems: 0, }; @@ -208,7 +211,7 @@ export class AuthorizedEntitiesCatalog implements EntitiesCatalog { allOf: [permissionFilter, basicEntityFilter({ 'metadata.uid': uid })], }, }); - if (entities.length === 0) { + if (entities.entities.length === 0) { throw new NotAllowedError(); } } diff --git a/plugins/catalog-backend/src/service/CatalogBuilder.ts b/plugins/catalog-backend/src/service/CatalogBuilder.ts index 31ec40b887..7ce308e796 100644 --- a/plugins/catalog-backend/src/service/CatalogBuilder.ts +++ b/plugins/catalog-backend/src/service/CatalogBuilder.ts @@ -115,6 +115,7 @@ import { UrlReaderService, SchedulerService, } from '@backstage/backend-plugin-api'; +import { entitiesResponseToObjects } from './response'; /** * This is a duplicate of the alpha `CatalogPermissionRule` type, for use in the stable API. @@ -485,6 +486,10 @@ export class CatalogBuilder { discovery, }); + const disableRelationsCompatibility = config.getOptionalBoolean( + 'catalog.disableRelationsCompatibility', + ); + const policy = this.buildEntityPolicy(); const processors = this.buildProcessors(); const parser = this.parser || defaultEntityDataParser; @@ -521,6 +526,7 @@ export class CatalogBuilder { database: dbClient, logger, stitcher, + disableRelationsCompatibility, }); let permissionsService: PermissionsService; @@ -566,7 +572,10 @@ export class CatalogBuilder { }, }); - const entitiesByRef = keyBy(entities, stringifyEntityRef); + const entitiesByRef = keyBy( + entitiesResponseToObjects(entities), + stringifyEntityRef, + ); return resourceRefs.map( resourceRef => @@ -629,6 +638,7 @@ export class CatalogBuilder { auth, httpAuth, permissionsService, + disableRelationsCompatibility, }); await connectEntityProviders(providerDatabase, entityProviders); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts index d2ac0871a9..070b93ab2c 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.test.ts @@ -38,6 +38,7 @@ import { Stitcher } from '../stitching/types'; import { DefaultEntitiesCatalog } from './DefaultEntitiesCatalog'; import { EntitiesRequest } from '../catalog/types'; import { buildEntitySearch } from '../database/operations/stitcher/buildEntitySearch'; +import { entitiesResponseToObjects } from './response'; jest.setTimeout(60_000); @@ -310,10 +311,11 @@ describe('DefaultEntitiesCatalog', () => { const testFilter = { key: 'spec.test', }; - const { entities } = await catalog.entities({ + const res = await catalog.entities({ filter: testFilter, credentials: mockCredentials.none(), }); + const entities = entitiesResponseToObjects(res.entities); expect(entities.length).toBe(1); expect(entities[0]).toEqual(entity2); @@ -351,10 +353,11 @@ describe('DefaultEntitiesCatalog', () => { key: 'spec.test', }, }; - const { entities } = await catalog.entities({ + const res = await catalog.entities({ filter: testFilter, credentials: mockCredentials.none(), }); + const entities = entitiesResponseToObjects(res.entities); expect(entities.length).toBe(1); expect(entities[0]).toEqual(entity1); @@ -416,7 +419,7 @@ describe('DefaultEntitiesCatalog', () => { values: ['red'], }, }; - const { entities } = await catalog.entities({ + const res = await catalog.entities({ filter: { allOf: [ testFilter1, @@ -427,6 +430,7 @@ describe('DefaultEntitiesCatalog', () => { }, credentials: mockCredentials.none(), }); + const entities = entitiesResponseToObjects(res.entities); expect(entities.length).toBe(2); expect(entities).toContainEqual(entity2); @@ -465,7 +469,7 @@ describe('DefaultEntitiesCatalog', () => { const testFilter2 = { key: 'metadata.desc', }; - const { entities } = await catalog.entities({ + const res = await catalog.entities({ filter: { not: { allOf: [testFilter1, testFilter2], @@ -474,6 +478,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }); + const entities = entitiesResponseToObjects(res.entities); expect(entities.length).toBe(1); expect(entities).toContainEqual(entity1); @@ -509,10 +514,11 @@ describe('DefaultEntitiesCatalog', () => { key: 'kind', values: [], }; - const { entities } = await catalog.entities({ + const res = await catalog.entities({ filter: testFilter, credentials: mockCredentials.none(), }); + const entities = entitiesResponseToObjects(res.entities); expect(entities.length).toBe(0); }, @@ -553,10 +559,11 @@ describe('DefaultEntitiesCatalog', () => { stitcher, }); - const { entities } = await catalog.entities(); + const res = await catalog.entities(); + const entities = entitiesResponseToObjects(res.entities); expect( - entities.find(e => e.metadata.name === 'one')!.relations, + entities.find(e => e?.metadata.name === 'one')!.relations, ).toEqual([ { type: 'r', @@ -565,7 +572,7 @@ describe('DefaultEntitiesCatalog', () => { }, ]); expect( - entities.find(e => e.metadata.name === 'two')!.relations, + entities.find(e => e?.metadata.name === 'two')!.relations, ).toEqual([ { type: 'r', @@ -615,7 +622,9 @@ describe('DefaultEntitiesCatalog', () => { return catalog .entities({ ...request, credentials: mockCredentials.none() }) .then(response => - response.entities.map(e => e.metadata.name).toSorted(), + entitiesResponseToObjects(response.entities) + .map(e => e!.metadata.name) + .toSorted(), ); } @@ -678,7 +687,11 @@ describe('DefaultEntitiesCatalog', () => { ): Promise { return catalog .entities({ ...request, credentials: mockCredentials.none() }) - .then(response => response.entities.map(e => e.metadata.name)); + .then(response => + entitiesResponseToObjects(response.entities).map( + e => e!.metadata.name, + ), + ); } await expect( @@ -764,7 +777,7 @@ describe('DefaultEntitiesCatalog', () => { stitcher, }); - const { items } = await catalog.entitiesBatch({ + const res = await catalog.entitiesBatch({ entityRefs: [ 'k:default/two', 'k:default/one', @@ -775,6 +788,7 @@ describe('DefaultEntitiesCatalog', () => { ], credentials: mockCredentials.none(), }); + const items = entitiesResponseToObjects(res.items); expect(items.map(e => e && stringifyEntityRef(e))).toEqual([ 'k:default/two', @@ -819,11 +833,12 @@ describe('DefaultEntitiesCatalog', () => { stitcher, }); - const { items } = await catalog.entitiesBatch({ + const res = await catalog.entitiesBatch({ entityRefs: ['k:default/two', 'k:default/one'], filter: { key: 'spec.owner', values: ['me'] }, credentials: mockCredentials.none(), }); + const items = entitiesResponseToObjects(res.items); expect(items.map(e => e && stringifyEntityRef(e))).toEqual([ 'k:default/two', @@ -881,7 +896,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response1 = await catalog.queryEntities(request1); - expect(response1.items).toEqual([entityFrom('A'), entityFrom('B')]); + expect(entitiesResponseToObjects(response1.items)).toEqual([ + entityFrom('A'), + entityFrom('B'), + ]); expect(response1.pageInfo.nextCursor).toBeDefined(); expect(response1.pageInfo.prevCursor).toBeUndefined(); expect(response1.totalItems).toBe(names.length); @@ -893,7 +911,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response2 = await catalog.queryEntities(request2); - expect(response2.items).toEqual([entityFrom('C'), entityFrom('D')]); + expect(entitiesResponseToObjects(response2.items)).toEqual([ + entityFrom('C'), + entityFrom('D'), + ]); expect(response2.pageInfo.nextCursor).toBeDefined(); expect(response2.pageInfo.prevCursor).toBeDefined(); expect(response2.totalItems).toBe(names.length); @@ -905,7 +926,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response3 = await catalog.queryEntities(request3); - expect(response3.items).toEqual([entityFrom('E'), entityFrom('F')]); + expect(entitiesResponseToObjects(response3.items)).toEqual([ + entityFrom('E'), + entityFrom('F'), + ]); expect(response3.pageInfo.nextCursor).toBeDefined(); expect(response3.pageInfo.prevCursor).toBeDefined(); expect(response3.totalItems).toBe(names.length); @@ -917,7 +941,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response4 = await catalog.queryEntities(request4); - expect(response4.items).toEqual([entityFrom('C'), entityFrom('D')]); + expect(entitiesResponseToObjects(response4.items)).toEqual([ + entityFrom('C'), + entityFrom('D'), + ]); expect(response4.pageInfo.nextCursor).toBeDefined(); expect(response4.pageInfo.prevCursor).toBeDefined(); expect(response4.totalItems).toBe(names.length); @@ -929,7 +956,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response5 = await catalog.queryEntities(request5); - expect(response5.items).toEqual([entityFrom('A'), entityFrom('B')]); + expect(entitiesResponseToObjects(response5.items)).toEqual([ + entityFrom('A'), + entityFrom('B'), + ]); expect(response5.pageInfo.nextCursor).toBeDefined(); expect(response5.pageInfo.prevCursor).toBeUndefined(); expect(response5.totalItems).toBe(names.length); @@ -941,7 +971,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response6 = await catalog.queryEntities(request6); - expect(response6.items).toEqual([entityFrom('C'), entityFrom('D')]); + expect(entitiesResponseToObjects(response6.items)).toEqual([ + entityFrom('C'), + entityFrom('D'), + ]); expect(response6.pageInfo.nextCursor).toBeDefined(); expect(response6.pageInfo.prevCursor).toBeDefined(); expect(response6.totalItems).toBe(names.length); @@ -953,7 +986,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response7 = await catalog.queryEntities(request7); - expect(response7.items).toEqual([entityFrom('E'), entityFrom('F')]); + expect(entitiesResponseToObjects(response7.items)).toEqual([ + entityFrom('E'), + entityFrom('F'), + ]); expect(response7.pageInfo.nextCursor).toBeDefined(); expect(response7.pageInfo.prevCursor).toBeDefined(); expect(response7.totalItems).toBe(names.length); @@ -965,7 +1001,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response7bis = await catalog.queryEntities(request7bis); - expect(response7bis.items).toEqual([ + expect(entitiesResponseToObjects(response7bis.items)).toEqual([ entityFrom('E'), entityFrom('F'), entityFrom('G'), @@ -981,7 +1017,9 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response8 = await catalog.queryEntities(request8); - expect(response8.items).toEqual([entityFrom('G')]); + expect(entitiesResponseToObjects(response8.items)).toEqual([ + entityFrom('G'), + ]); expect(response8.pageInfo.nextCursor).toBeUndefined(); expect(response8.pageInfo.prevCursor).toBeDefined(); expect(response8.totalItems).toBe(names.length); @@ -1035,7 +1073,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response1 = await catalog.queryEntities(request1); - expect(response1.items).toEqual([entityFrom('G'), entityFrom('F')]); + expect(entitiesResponseToObjects(response1.items)).toEqual([ + entityFrom('G'), + entityFrom('F'), + ]); expect(response1.pageInfo.nextCursor).toBeDefined(); expect(response1.pageInfo.prevCursor).toBeUndefined(); expect(response1.totalItems).toBe(names.length); @@ -1047,7 +1088,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response2 = await catalog.queryEntities(request2); - expect(response2.items).toEqual([entityFrom('E'), entityFrom('D')]); + expect(entitiesResponseToObjects(response2.items)).toEqual([ + entityFrom('E'), + entityFrom('D'), + ]); expect(response2.pageInfo.nextCursor).toBeDefined(); expect(response2.pageInfo.prevCursor).toBeDefined(); expect(response2.totalItems).toBe(names.length); @@ -1059,7 +1103,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response3 = await catalog.queryEntities(request3); - expect(response3.items).toEqual([entityFrom('C'), entityFrom('B')]); + expect(entitiesResponseToObjects(response3.items)).toEqual([ + entityFrom('C'), + entityFrom('B'), + ]); expect(response3.pageInfo.nextCursor).toBeDefined(); expect(response3.pageInfo.prevCursor).toBeDefined(); expect(response3.totalItems).toBe(names.length); @@ -1072,7 +1119,10 @@ describe('DefaultEntitiesCatalog', () => { }; const response4 = await catalog.queryEntities(request4); - expect(response4.items).toEqual([entityFrom('E'), entityFrom('D')]); + expect(entitiesResponseToObjects(response4.items)).toEqual([ + entityFrom('E'), + entityFrom('D'), + ]); expect(response4.pageInfo.nextCursor).toBeDefined(); expect(response4.pageInfo.prevCursor).toBeDefined(); expect(response4.totalItems).toBe(names.length); @@ -1084,7 +1134,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response5 = await catalog.queryEntities(request5); - expect(response5.items).toEqual([entityFrom('G'), entityFrom('F')]); + expect(entitiesResponseToObjects(response5.items)).toEqual([ + entityFrom('G'), + entityFrom('F'), + ]); expect(response5.pageInfo.nextCursor).toBeDefined(); expect(response5.pageInfo.prevCursor).toBeUndefined(); expect(response5.totalItems).toBe(names.length); @@ -1096,7 +1149,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response6 = await catalog.queryEntities(request6); - expect(response6.items).toEqual([entityFrom('E'), entityFrom('D')]); + expect(entitiesResponseToObjects(response6.items)).toEqual([ + entityFrom('E'), + entityFrom('D'), + ]); expect(response6.pageInfo.nextCursor).toBeDefined(); expect(response6.pageInfo.prevCursor).toBeDefined(); expect(response6.totalItems).toBe(names.length); @@ -1108,7 +1164,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response7 = await catalog.queryEntities(request7); - expect(response7.items).toEqual([entityFrom('C'), entityFrom('B')]); + expect(entitiesResponseToObjects(response7.items)).toEqual([ + entityFrom('C'), + entityFrom('B'), + ]); expect(response7.pageInfo.nextCursor).toBeDefined(); expect(response7.pageInfo.prevCursor).toBeDefined(); expect(response7.totalItems).toBe(names.length); @@ -1120,7 +1179,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response7bis = await catalog.queryEntities(request7bis); - expect(response7bis.items).toEqual([ + expect(entitiesResponseToObjects(response7bis.items)).toEqual([ entityFrom('C'), entityFrom('B'), entityFrom('A'), @@ -1136,7 +1195,9 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response8 = await catalog.queryEntities(request8); - expect(response8.items).toEqual([entityFrom('A')]); + expect(entitiesResponseToObjects(response8.items)).toEqual([ + entityFrom('A'), + ]); expect(response8.pageInfo.nextCursor).toBeUndefined(); expect(response8.pageInfo.prevCursor).toBeDefined(); expect(response8.totalItems).toBe(names.length); @@ -1183,13 +1244,12 @@ describe('DefaultEntitiesCatalog', () => { const request: QueryEntitiesInitialRequest = { filter, limit: 100, - orderFields: [{ field: 'metadata.name', order: 'asc' }], fullTextFilter: { term: 'cAt ' }, credentials: mockCredentials.none(), }; const response = await catalog.queryEntities(request); - expect(response.items).toEqual([ + expect(entitiesResponseToObjects(response.items)).toEqual([ entityFrom('atcatss'), entityFrom('cat'), entityFrom('dogcat'), @@ -1200,6 +1260,60 @@ describe('DefaultEntitiesCatalog', () => { }, ); + it.each(databases.eachSupportedId())( + 'should filter the results when query is provided with fullTextFilter for camelCase fields, %p', + async databaseId => { + await createDatabase(databaseId); + + const entities: Entity[] = [ + { + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'camelCase', + }, + spec: { + shouldSearchCamelCase: 'searched', + }, + }, + ]; + + const notFoundEntities: Entity[] = [ + { + apiVersion: 'a', + kind: 'k', + metadata: { name: 'something' }, + spec: {}, + }, + ]; + + await Promise.all( + entities.concat(notFoundEntities).map(e => addEntityToSearch(e)), + ); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: mockServices.logger.mock(), + stitcher, + }); + + const request: QueryEntitiesInitialRequest = { + limit: 100, + orderFields: [{ field: 'metadata.name', order: 'asc' }], + fullTextFilter: { + term: 'sear', + fields: ['spec.shouldSearchCamelCase'], + }, + credentials: mockCredentials.none(), + }; + const response = await catalog.queryEntities(request); + expect(entitiesResponseToObjects(response.items)).toEqual(entities); + expect(response.pageInfo.nextCursor).toBeUndefined(); + expect(response.pageInfo.prevCursor).toBeUndefined(); + expect(response.totalItems).toBe(1); + }, + ); + it.each(databases.eachSupportedId())( 'should filter the text results when sortOrder is not provided, %p', async databaseId => { @@ -1248,7 +1362,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response = await catalog.queryEntities(request); - expect(response.items).toEqual([ + expect(entitiesResponseToObjects(response.items)).toEqual([ entityFrom('1', { uid: 'id1', title: 'cat' }), entityFrom('2', { uid: 'id2', title: 'atcatss' }), entityFrom('4', { uid: 'id4', title: 'dogcat' }), @@ -1261,7 +1375,7 @@ describe('DefaultEntitiesCatalog', () => { ...request, limit: 2, }); - expect(paginatedResponse.items).toEqual([ + expect(entitiesResponseToObjects(paginatedResponse.items)).toEqual([ entityFrom('1', { uid: 'id1', title: 'cat' }), entityFrom('2', { uid: 'id2', title: 'atcatss' }), ]); @@ -1273,7 +1387,7 @@ describe('DefaultEntitiesCatalog', () => { cursor: paginatedResponse.pageInfo.nextCursor!, credentials: mockCredentials.none(), }); - expect(paginatedResponseNext.items).toEqual([ + expect(entitiesResponseToObjects(paginatedResponseNext.items)).toEqual([ entityFrom('4', { uid: 'id4', title: 'dogcat' }), ]); expect(paginatedResponseNext.pageInfo.nextCursor).toBeUndefined(); @@ -1351,7 +1465,7 @@ describe('DefaultEntitiesCatalog', () => { }; const response = await catalog.queryEntities(request); - expect(response.items).toEqual([ + expect(entitiesResponseToObjects(response.items)).toEqual([ entityFrom('KingOfTheJungle', { uid: 'id0', title: 'lion' }), entityFrom('NotKingOfTheJungle', { uid: 'id1', title: 'cat' }), entityFrom('NotACatKing', { uid: 'id2', title: 'atcatss' }), @@ -1365,7 +1479,7 @@ describe('DefaultEntitiesCatalog', () => { ...request, limit: 2, }); - expect(paginatedResponse.items).toEqual([ + expect(entitiesResponseToObjects(paginatedResponse.items)).toEqual([ entityFrom('KingOfTheJungle', { uid: 'id0', title: 'lion' }), entityFrom('NotKingOfTheJungle', { uid: 'id1', title: 'cat' }), ]); @@ -1377,7 +1491,7 @@ describe('DefaultEntitiesCatalog', () => { cursor: paginatedResponse.pageInfo.nextCursor!, credentials: mockCredentials.none(), }); - expect(paginatedResponseNext.items).toEqual([ + expect(entitiesResponseToObjects(paginatedResponseNext.items)).toEqual([ entityFrom('NotACatKing', { uid: 'id2', title: 'atcatss' }), entityFrom('123', { uid: 'id3', title: 'king' }), ]); @@ -1421,7 +1535,63 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response = await catalog.queryEntities(request); - expect(response).toEqual({ totalItems: 20, items: [], pageInfo: {} }); + expect(response).toEqual({ + totalItems: 20, + items: { type: 'raw', entities: [] }, + pageInfo: {}, + }); + }, + ); + + it.each(databases.eachSupportedId())( + 'can skip totalItems, %p', + async databaseId => { + await createDatabase(databaseId); + + await Promise.all( + Array(15) + .fill(0) + .map(() => + addEntityToSearch({ + apiVersion: 'a', + kind: 'k', + metadata: { name: v4() }, + }), + ), + ); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: mockServices.logger.mock(), + stitcher, + }); + + const request: QueryEntitiesInitialRequest = { + limit: 10, + credentials: mockCredentials.none(), + skipTotalItems: true, + }; + let response = await catalog.queryEntities(request); + expect(response).toEqual({ + totalItems: 0, + items: { + type: 'raw', + entities: expect.objectContaining({ length: 10 }), + }, + pageInfo: { nextCursor: expect.anything() }, + }); + response = await catalog.queryEntities({ + ...request, + cursor: response.pageInfo.nextCursor!, + }); + expect(response).toEqual({ + totalItems: 0, + items: { + type: 'raw', + entities: expect.objectContaining({ length: 5 }), + }, + pageInfo: { prevCursor: expect.anything() }, + }); }, ); @@ -1454,7 +1624,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response1 = await catalog.queryEntities(request1); - expect(response1.items).toMatchObject([ + expect(entitiesResponseToObjects(response1.items)).toMatchObject([ entityFrom('AA'), entityFrom('AA'), ]); @@ -1469,7 +1639,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response2 = await catalog.queryEntities(request2); - expect(response2.items).toMatchObject([ + expect(entitiesResponseToObjects(response2.items)).toMatchObject([ entityFrom('AA'), entityFrom('AA'), ]); @@ -1484,7 +1654,10 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response3 = await catalog.queryEntities(request3); - expect(response3.items).toEqual([entityFrom('CC'), entityFrom('DD')]); + expect(entitiesResponseToObjects(response3.items)).toEqual([ + entityFrom('CC'), + entityFrom('DD'), + ]); expect(response3.pageInfo.nextCursor).toBeUndefined(); expect(response3.pageInfo.prevCursor).toBeDefined(); expect(response3.totalItems).toBe(6); @@ -1496,7 +1669,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response4 = await catalog.queryEntities(request4); - expect(response4.items).toMatchObject([ + expect(entitiesResponseToObjects(response4.items)).toMatchObject([ entityFrom('AA'), entityFrom('AA'), ]); @@ -1511,7 +1684,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response5 = await catalog.queryEntities(request5); - expect(response5.items).toMatchObject([ + expect(entitiesResponseToObjects(response5.items)).toMatchObject([ entityFrom('AA'), entityFrom('AA'), ]); @@ -1579,7 +1752,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response1 = await catalog.queryEntities(request1); - expect(response1.items).toMatchObject([ + expect(entitiesResponseToObjects(response1.items)).toMatchObject([ entityFrom('AA', { uid: '1', kind: 'included' }), entityFrom('AA', { uid: '2', kind: 'included' }), ]); @@ -1594,7 +1767,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response2 = await catalog.queryEntities(request2); - expect(response2.items).toMatchObject([ + expect(entitiesResponseToObjects(response2.items)).toMatchObject([ entityFrom('AA', { uid: '4', kind: 'included' }), entityFrom('AA', { uid: '5', kind: 'included' }), ]); @@ -1638,7 +1811,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response1 = await catalog.queryEntities(request1); - expect(response1.items).toMatchObject([ + expect(entitiesResponseToObjects(response1.items)).toMatchObject([ entityFrom('AA'), entityFrom('CC'), ]); @@ -1653,7 +1826,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response2 = await catalog.queryEntities(request2); - expect(response2.items).toMatchObject([ + expect(entitiesResponseToObjects(response2.items)).toMatchObject([ entityFrom('DD'), entityFrom('AA', { namespace: 'namespace2' }), ]); @@ -1668,7 +1841,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response3 = await catalog.queryEntities(request3); - expect(response3.items).toMatchObject([ + expect(entitiesResponseToObjects(response3.items)).toMatchObject([ entityFrom('AA', { namespace: 'namespace3' }), entityFrom('AA', { namespace: 'namespace4' }), ]); @@ -1683,7 +1856,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response4 = await catalog.queryEntities(request4); - expect(response4.items).toMatchObject([ + expect(entitiesResponseToObjects(response4.items)).toMatchObject([ entityFrom('DD'), entityFrom('AA', { namespace: 'namespace2' }), ]); @@ -1698,7 +1871,7 @@ describe('DefaultEntitiesCatalog', () => { credentials: mockCredentials.none(), }; const response5 = await catalog.queryEntities(request5); - expect(response5.items).toMatchObject([ + expect(entitiesResponseToObjects(response5.items)).toMatchObject([ entityFrom('AA'), entityFrom('CC'), ]); @@ -1731,7 +1904,9 @@ describe('DefaultEntitiesCatalog', () => { orderFields: [{ field: 'metadata.title', order: 'asc' }], credentials: mockCredentials.none(), }) - .then(r => r.items.map(e => e.metadata.name)), + .then(r => + entitiesResponseToObjects(r.items).map(e => e!.metadata.name), + ), ).resolves.toEqual(['CC', 'BB', 'AA']); // 'AA' has no title, ends up last await expect( @@ -1740,10 +1915,61 @@ describe('DefaultEntitiesCatalog', () => { orderFields: [{ field: 'metadata.title', order: 'desc' }], credentials: mockCredentials.none(), }) - .then(r => r.items.map(e => e.metadata.name)), + .then(r => + entitiesResponseToObjects(r.items).map(e => e!.metadata.name), + ), ).resolves.toEqual(['BB', 'CC', 'AA']); // 'AA' has no title, ends up last }, ); + + it.each(databases.eachSupportedId())( + 'should silently skip over entities that are not yet stitched, %p', + async databaseId => { + await createDatabase(databaseId); + + const entity1 = entityFrom('AA', { uid: 'id1' }); + const entity2 = entityFrom('BB', { uid: 'id2' }); + await Promise.all([ + addEntityToSearch(entity1), + addEntityToSearch(entity2), + ]); + + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: mockServices.logger.mock(), + stitcher, + }); + + await expect( + catalog + .queryEntities({ + orderFields: [{ field: 'metadata.uid', order: 'asc' }], + limit: 10, + credentials: mockCredentials.none(), + }) + .then(r => + entitiesResponseToObjects(r.items).map(e => e!.metadata.name), + ), + ).resolves.toEqual(['AA', 'BB']); + + // simulate a situation where stitching is not yet complete + await knex('final_entities') + .update({ final_entity: null }) + .where({ entity_ref: stringifyEntityRef(entity1) }); + + await expect( + catalog + .queryEntities({ + orderFields: [{ field: 'metadata.uid', order: 'asc' }], + limit: 10, + credentials: mockCredentials.none(), + }) + .then(r => + entitiesResponseToObjects(r.items).map(e => e!.metadata.name), + ), + ).resolves.toEqual(['BB']); + }, + ); }); describe('removeEntityByUid', () => { @@ -2007,6 +2233,50 @@ describe('DefaultEntitiesCatalog', () => { }); }, ); + + it.each(databases.eachSupportedId())( + 'works with a mixture of present and missing facets, %p', + async databaseId => { + await createDatabase(databaseId); + + await addEntityToSearch({ + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'one', + }, + spec: {}, + }); + await addEntityToSearch({ + apiVersion: 'a', + kind: 'k', + metadata: { + name: 'two', + }, + spec: {}, + }); + const catalog = new DefaultEntitiesCatalog({ + database: knex, + logger: mockServices.logger.mock(), + stitcher, + }); + + await expect( + catalog.facets({ + facets: ['metadata.name', 'missing'], + credentials: mockCredentials.none(), + }), + ).resolves.toEqual({ + facets: { + 'metadata.name': expect.arrayContaining([ + { value: 'one', count: 1 }, + { value: 'two', count: 1 }, + ]), + missing: [], + }, + }); + }, + ); }); }); diff --git a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts index d1cabbf575..f0e0667bef 100644 --- a/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts +++ b/plugins/catalog-backend/src/service/DefaultEntitiesCatalog.ts @@ -14,11 +14,7 @@ * limitations under the License. */ -import { - Entity, - parseEntityRef, - stringifyEntityRef, -} from '@backstage/catalog-model'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; import { InputError, NotFoundError } from '@backstage/errors'; import { Knex } from 'knex'; import { chunk as lodashChunk, isEqual } from 'lodash'; @@ -49,21 +45,16 @@ import { import { Stitcher } from '../stitching/types'; import { + expandLegacyCompoundRelationsInEntity, isQueryEntitiesCursorRequest, isQueryEntitiesInitialRequest, } from './util'; -import { - EntitiesSearchFilter, - EntityFilter, -} from '@backstage/plugin-catalog-node'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; import { LoggerService } from '@backstage/backend-plugin-api'; +import { applyEntityFilterToQuery } from './request/applyEntityFilterToQuery'; +import { processRawEntitiesResult } from './response'; -const defaultSortField: EntityOrder = { - field: 'metadata.uid', - order: 'asc', -}; - -const DEFAULT_LIMIT = 20; +const DEFAULT_LIMIT = 200; function parsePagination(input?: EntityPagination): EntityPagination { if (!input) { @@ -110,101 +101,29 @@ function stringifyPagination( return base64; } -function addCondition( - queryBuilder: Knex.QueryBuilder, - db: Knex, - filter: EntitiesSearchFilter, - negate: boolean = false, - entityIdField = 'entity_id', -): void { - const key = filter.key.toLowerCase(); - const values = filter.values?.map(v => v.toLowerCase()); - - // NOTE(freben): This used to be a set of OUTER JOIN, which may seem to - // make a lot of sense. However, it had abysmal performance on sqlite - // when datasets grew large, so we're using IN instead. - const matchQuery = db('search') - .select('search.entity_id') - .where({ key }) - .andWhere(function keyFilter() { - if (values?.length === 1) { - this.where({ value: values.at(0) }); - } else if (values) { - this.andWhere('value', 'in', values); - } - }); - queryBuilder.andWhere(entityIdField, negate ? 'not in' : 'in', matchQuery); -} - -function isEntitiesSearchFilter( - filter: EntitiesSearchFilter | EntityFilter, -): filter is EntitiesSearchFilter { - return filter.hasOwnProperty('key'); -} - -function isOrEntityFilter( - filter: { anyOf: EntityFilter[] } | EntityFilter, -): filter is { anyOf: EntityFilter[] } { - return filter.hasOwnProperty('anyOf'); -} - -function isNegationEntityFilter( - filter: { not: EntityFilter } | EntityFilter, -): filter is { not: EntityFilter } { - return filter.hasOwnProperty('not'); -} - -function parseFilter( - filter: EntityFilter, - query: Knex.QueryBuilder, - db: Knex, - negate: boolean = false, - entityIdField = 'entity_id', -): Knex.QueryBuilder { - if (isNegationEntityFilter(filter)) { - return parseFilter(filter.not, query, db, !negate, entityIdField); - } - - if (isEntitiesSearchFilter(filter)) { - return query.andWhere(function filterFunction() { - addCondition(this, db, filter, negate, entityIdField); - }); - } - - return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() { - if (isOrEntityFilter(filter)) { - for (const subFilter of filter.anyOf ?? []) { - this.orWhere(subQuery => - parseFilter(subFilter, subQuery, db, false, entityIdField), - ); - } - } else { - for (const subFilter of filter.allOf ?? []) { - this.andWhere(subQuery => - parseFilter(subFilter, subQuery, db, false, entityIdField), - ); - } - } - }); -} - export class DefaultEntitiesCatalog implements EntitiesCatalog { private readonly database: Knex; private readonly logger: LoggerService; private readonly stitcher: Stitcher; + private readonly disableRelationsCompatibility: boolean; constructor(options: { database: Knex; logger: LoggerService; stitcher: Stitcher; + disableRelationsCompatibility?: boolean; }) { this.database = options.database; this.logger = options.logger; this.stitcher = options.stitcher; + this.disableRelationsCompatibility = Boolean( + options.disableRelationsCompatibility, + ); } async entities(request?: EntitiesRequest): Promise { const db = this.database; + const { limit, offset } = parsePagination(request?.pagination); let entitiesQuery = db('final_entities').select('final_entities.*'); @@ -224,13 +143,12 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { entitiesQuery = entitiesQuery.whereNotNull('final_entities.final_entity'); if (request?.filter) { - entitiesQuery = parseFilter( - request.filter, - entitiesQuery, - db, - false, - 'final_entities.entity_id', - ); + entitiesQuery = applyEntityFilterToQuery({ + filter: request.filter, + targetQuery: entitiesQuery, + onEntityIdField: 'final_entities.entity_id', + knex: db, + }); } request?.order?.forEach(({ order }, index) => { @@ -256,7 +174,6 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { entitiesQuery.orderBy('final_entities.entity_id', 'asc'); // stable sort } - const { limit, offset } = parsePagination(request?.pagination); if (limit !== undefined) { entitiesQuery = entitiesQuery.limit(limit + 1); } @@ -279,36 +196,19 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { }; } - let entities: Entity[] = rows.map(e => JSON.parse(e.final_entity!)); - - if (request?.fields) { - entities = entities.map(e => request.fields!(e)); - } - - // TODO(freben): This is added as a compatibility guarantee, until we can be - // sure that all adopters have re-stitched their entities so that the new - // targetRef field is present on them, and that they have stopped consuming - // the now-removed old field - // TODO(jhaals): Remove this in April 2022 - for (const entity of entities) { - if (entity.relations) { - for (const relation of entity.relations as any) { - if (!relation.targetRef && relation.target) { - // This is the case where an old-form entity, not yet stitched with - // the updated code, was in the database - relation.targetRef = stringifyEntityRef(relation.target); - } else if (!relation.target && relation.targetRef) { - // This is the case where a new-form entity, stitched with the - // updated code, was in the database but we still want to produce - // the old data shape as well for compatibility reasons - relation.target = parseEntityRef(relation.targetRef); - } - } - } - } - return { - entities, + entities: processRawEntitiesResult( + rows.map(r => r.final_entity!), + this.disableRelationsCompatibility + ? request?.fields + : e => { + expandLegacyCompoundRelationsInEntity(e); + if (request?.fields) { + return request.fields(e); + } + return e; + }, + ), pageInfo, }; } @@ -316,7 +216,7 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { async entitiesBatch( request: EntitiesBatchRequest, ): Promise { - const lookup = new Map(); + const lookup = new Map(); for (const chunk of lodashChunk(request.entityRefs, 200)) { let query = this.database('final_entities') @@ -327,136 +227,194 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { .whereIn('final_entities.entity_ref', chunk); if (request?.filter) { - query = parseFilter( - request.filter, - query, - this.database, - false, - 'final_entities.entity_id', - ); + query = applyEntityFilterToQuery({ + filter: request.filter, + targetQuery: query, + onEntityIdField: 'final_entities.entity_id', + knex: this.database, + }); } for (const row of await query) { - lookup.set(row.entityRef, row.entity ? JSON.parse(row.entity) : null); + lookup.set(row.entityRef, row.entity ? row.entity : null); } } - let items = request.entityRefs.map(ref => lookup.get(ref) ?? null); + const items = request.entityRefs.map(ref => lookup.get(ref) ?? null); - if (request.fields) { - items = items.map(e => e && request.fields!(e)); - } - - return { items }; + return { items: processRawEntitiesResult(items, request.fields) }; } async queryEntities( request: QueryEntitiesRequest, ): Promise { - const db = this.database; - const limit = request.limit ?? DEFAULT_LIMIT; const cursor: Omit & { orderFieldValues?: (string | null)[]; + skipTotalItems: boolean; } = { - orderFields: [defaultSortField], + orderFields: [], isPrevious: false, ...parseCursorFromRequest(request), }; + // For performance reasons we invoke the count query only on the first + // request. The result is then embedded into the cursor for subsequent + // requests. Threfore this can be undefined here, but will then get + // populated further down. + const shouldComputeTotalItems = + cursor.totalItems === undefined && !cursor.skipTotalItems; const isFetchingBackwards = cursor.isPrevious; if (cursor.orderFields.length > 1) { this.logger.warn(`Only one sort field is supported, ignoring the rest`); } - const sortField: EntityOrder = { - ...defaultSortField, - ...cursor.orderFields[0], - }; + const sortField = cursor.orderFields.at(0); - const [prevItemOrderFieldValue, prevItemUid] = - cursor.orderFieldValues || []; + // The first part of the query builder is a subquery that applies all of the + // filtering. + const dbQuery = this.database.with( + 'filtered', + ['entity_id', 'final_entity', ...(sortField ? ['value'] : [])], + inner => { + inner + .from('final_entities') + .whereNotNull('final_entity'); - const dbQuery = db('final_entities').leftOuterJoin('search', qb => - qb - .on('search.entity_id', 'final_entities.entity_id') - .andOnVal('search.key', sortField.field), - ); + if (sortField) { + inner + .leftOuterJoin('search', qb => + qb + .on('search.entity_id', 'final_entities.entity_id') + .andOnVal('search.key', sortField.field), + ) + .select({ + entity_id: 'final_entities.entity_id', + final_entity: 'final_entities.final_entity', + value: 'search.value', + }); + } else { + inner.select({ + entity_id: 'final_entities.entity_id', + final_entity: 'final_entities.final_entity', + }); + } - if (cursor.filter) { - parseFilter( - cursor.filter, - dbQuery, - db, - false, - 'final_entities.entity_id', - ); - } + // Add regular filters, if given + if (cursor.filter) { + applyEntityFilterToQuery({ + filter: cursor.filter, + targetQuery: inner, + onEntityIdField: 'final_entities.entity_id', + knex: this.database, + }); + } - const normalizedFullTextFilterTerm = cursor.fullTextFilter?.term?.trim(); - const textFilterFields = cursor.fullTextFilter?.fields ?? [sortField.field]; - if (normalizedFullTextFilterTerm) { - if ( - textFilterFields.length === 1 && - textFilterFields[0] === sortField.field - ) { - // If there is one item, apply the like query to the top level query which is already - // filtered based on the singular sortField. - dbQuery.andWhereRaw( - 'value like ?', - `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`, - ); - } else { - const matchQuery = db('search') - .select('search.entity_id') - .whereIn('key', textFilterFields) - .andWhere(function keyFilter() { - this.andWhereRaw( - 'value like ?', + // Add full text search filters, if given + const normalizedFullTextFilterTerm = + cursor.fullTextFilter?.term?.trim(); + const textFilterFields = cursor.fullTextFilter?.fields ?? [ + sortField?.field || 'metadata.uid', + ]; + if (normalizedFullTextFilterTerm) { + if ( + textFilterFields.length === 1 && + textFilterFields[0] === sortField?.field + ) { + // If there is one item, apply the like query to the top level query which is already + // filtered based on the singular sortField. + inner.andWhereRaw( + 'search.value like ?', `%${normalizedFullTextFilterTerm.toLocaleLowerCase('en-US')}%`, ); - }); - dbQuery.andWhere('final_entities.entity_id', 'in', matchQuery); + } else { + const matchQuery = this.database('search') + .select('search.entity_id') + // textFilterFields must be lowercased to match searchable keys in database, i.e. spec.profile.displayName -> spec.profile.displayname + .whereIn( + 'search.key', + textFilterFields.map(field => field.toLocaleLowerCase('en-US')), + ) + .andWhere(function keyFilter() { + this.andWhereRaw( + 'search.value like ?', + `%${normalizedFullTextFilterTerm.toLocaleLowerCase( + 'en-US', + )}%`, + ); + }); + inner.andWhere('final_entities.entity_id', 'in', matchQuery); + } + } + }, + ); + + // Only pay the cost of counting the number of items if needed + if (shouldComputeTotalItems) { + // Note the intentional cross join here. The filtered_count dataset is + // always exactly one row, so it won't grow the result unnecessarily. But + // it's also important that there IS at least one row, because even if the + // filtered dataset is empty, we still want to know the total number of + // items. + dbQuery + .with('filtered_count', ['count'], inner => + inner.from('filtered').count('*', { as: 'count' }), + ) + .fromRaw('filtered_count, filtered') + .select('count', 'filtered.*'); + } else { + dbQuery.from('filtered').select('*'); + } + + const isOrderingDescending = sortField?.order === 'desc'; + + // Move forward (or backward) in the set to the correct cursor position + if (cursor.orderFieldValues) { + if (cursor.orderFieldValues.length === 2) { + // The first will be the sortField value, the second the entity_id + const [first, second] = cursor.orderFieldValues; + dbQuery.andWhere(function nested() { + this.where( + 'filtered.value', + isFetchingBackwards !== isOrderingDescending ? '<' : '>', + first, + ) + .orWhere('filtered.value', '=', first) + .andWhere( + 'filtered.entity_id', + isFetchingBackwards !== isOrderingDescending ? '<' : '>', + second, + ); + }); + } else if (cursor.orderFieldValues.length === 1) { + // This will be the entity_id + const [first] = cursor.orderFieldValues; + dbQuery.andWhere('entity_id', isFetchingBackwards ? '<' : '>', first); } } - const countQuery = dbQuery.clone(); - - const isOrderingDescending = sortField.order === 'desc'; - - if (prevItemOrderFieldValue) { - dbQuery.andWhere(function nested() { - this.where( - 'value', - isFetchingBackwards !== isOrderingDescending ? '<' : '>', - prevItemOrderFieldValue, - ) - .orWhere('value', '=', prevItemOrderFieldValue) - .andWhere( - 'final_entities.entity_id', - isFetchingBackwards !== isOrderingDescending ? '<' : '>', - prevItemUid, - ); - }); + // Add the ordering + let order = sortField?.order ?? 'asc'; + if (isFetchingBackwards) { + order = invertOrder(order); } - - if (db.client.config.client === 'pg') { + if (this.database.client.config.client === 'pg') { // pg correctly orders by the column value and handling nulls in one go dbQuery.orderBy([ + ...(sortField + ? [ + { + column: 'filtered.value', + order, + nulls: 'last', + }, + ] + : []), { - column: 'search.value', - order: isFetchingBackwards - ? invertOrder(sortField.order) - : sortField.order, - nulls: 'last', - }, - { - column: 'final_entities.entity_id', - order: isFetchingBackwards - ? invertOrder(sortField.order) - : sortField.order, + column: 'filtered.entity_id', + order, }, ]); } else { @@ -464,26 +422,27 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { // no matter what the order is, for some reason, so we have to manually add back the statement // that translates to "order by value " while avoiding to give an order dbQuery.orderBy([ + ...(sortField + ? [ + { + column: 'filtered.value', + order: undefined, + nulls: 'last', + }, + { + column: 'filtered.value', + order, + }, + ] + : []), { - column: 'search.value', - order: undefined, - nulls: 'last', - }, - { - column: 'search.value', - order: isFetchingBackwards - ? invertOrder(sortField.order) - : sortField.order, - }, - { - column: 'final_entities.entity_id', - order: isFetchingBackwards - ? invertOrder(sortField.order) - : sortField.order, + column: 'filtered.entity_id', + order, }, ]); } + // Apply a manually set initial offset if ( isQueryEntitiesInitialRequest(request) && request.offset !== undefined @@ -493,20 +452,18 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { // fetch an extra item to check if there are more items. dbQuery.limit(isFetchingBackwards ? limit : limit + 1); - countQuery.count('final_entities.entity_id', { as: 'count' }); + const rows = shouldComputeTotalItems || limit > 0 ? await dbQuery : []; - const [rows, [{ count }]] = await Promise.all([ - limit > 0 ? dbQuery : [], - // for performance reasons we invoke the countQuery - // only on the first request. - // The result is then embedded into the cursor - // for subsequent requests. - typeof cursor.totalItems === 'undefined' - ? countQuery - : [{ count: cursor.totalItems }], - ]); - - const totalItems = Number(count); + let totalItems: number; + if (cursor.totalItems !== undefined) { + totalItems = cursor.totalItems; + } else if (cursor.skipTotalItems) { + totalItems = 0; + } else if (rows.length) { + totalItems = Number(rows[0].count); + } else { + totalItems = 0; + } if (isFetchingBackwards) { rows.reverse(); @@ -524,15 +481,13 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { const firstRow = rows[0]; const lastRow = rows[rows.length - 1]; - const firstSortFieldValues = cursor.firstSortFieldValues || [ - firstRow?.value, - firstRow?.entity_id, - ]; + const firstSortFieldValues = + cursor.firstSortFieldValues || sortFieldsFromRow(firstRow, sortField); const nextCursor: Cursor | undefined = hasMoreResults ? { ...cursor, - orderFieldValues: sortFieldsFromRow(lastRow), + orderFieldValues: sortFieldsFromRow(lastRow, sortField), firstSortFieldValues, isPrevious: false, totalItems, @@ -542,22 +497,24 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { const prevCursor: Cursor | undefined = !isInitialRequest && rows.length > 0 && - !isEqual(sortFieldsFromRow(firstRow), cursor.firstSortFieldValues) + !isEqual( + sortFieldsFromRow(firstRow, sortField), + cursor.firstSortFieldValues, + ) ? { ...cursor, - orderFieldValues: sortFieldsFromRow(firstRow), + orderFieldValues: sortFieldsFromRow(firstRow, sortField), firstSortFieldValues: cursor.firstSortFieldValues, isPrevious: true, totalItems, } : undefined; - const items = rows - .map(e => JSON.parse(e.final_entity!)) - .map(e => (request.fields ? request.fields(e) : e)); - return { - items, + items: processRawEntitiesResult( + rows.map(r => r.final_entity!), + request.fields, + ), pageInfo: { ...(!!prevCursor && { prevCursor }), ...(!!nextCursor && { nextCursor }), @@ -716,26 +673,39 @@ export class DefaultEntitiesCatalog implements EntitiesCatalog { } async facets(request: EntityFacetsRequest): Promise { + const query = this.database('search') + .whereIn( + 'search.key', + request.facets.map(f => f.toLocaleLowerCase('en-US')), + ) + .whereNotNull('search.original_value') + .select({ + facet: 'search.key', + value: 'search.original_value', + count: this.database.raw('count(*)'), + }) + .groupBy(['search.key', 'search.original_value']); + + if (request.filter) { + applyEntityFilterToQuery({ + filter: request.filter, + targetQuery: query, + onEntityIdField: 'search.entity_id', + knex: this.database, + }); + } + + const rows = await query; + const facets: EntityFacetsResponse['facets'] = {}; - const db = this.database; - for (const facet of request.facets) { - const dbQuery = db('search') - .where('search.key', facet.toLocaleLowerCase('en-US')) - .whereNotNull('search.original_value') - .select({ value: 'search.original_value', count: db.raw('count(*)') }) - .groupBy('search.original_value'); - - if (request?.filter) { - parseFilter(request.filter, dbQuery, db, false, 'search.entity_id'); - } - - const result = await dbQuery; - - facets[facet] = result.map(data => ({ - value: String(data.value), - count: Number(data.count), - })); + const facetLowercase = facet.toLocaleLowerCase('en-US'); + facets[facet] = rows + .filter(row => row.facet === facetLowercase) + .map(row => ({ + value: String(row.value), + count: Number(row.count), + })); } return { facets }; @@ -767,25 +737,35 @@ export const cursorParser: z.ZodSchema = z.object({ function parseCursorFromRequest( request?: QueryEntitiesRequest, -): Partial { +): Partial & { skipTotalItems: boolean } { if (isQueryEntitiesInitialRequest(request)) { const { filter, - orderFields: sortFields = [defaultSortField], + orderFields: sortFields = [], fullTextFilter, + skipTotalItems = false, } = request; - return { filter, orderFields: sortFields, fullTextFilter }; + return { filter, orderFields: sortFields, fullTextFilter, skipTotalItems }; } if (isQueryEntitiesCursorRequest(request)) { - return request.cursor; + return { + ...request.cursor, + // Doesn't matter here + skipTotalItems: false, + }; } - return {}; + return { + skipTotalItems: false, + }; } function invertOrder(order: EntityOrder['order']) { return order === 'asc' ? 'desc' : 'asc'; } -function sortFieldsFromRow(row: DbSearchRow) { - return [row.value, row.entity_id]; +function sortFieldsFromRow( + row: DbSearchRow & DbFinalEntitiesRow, + sortField?: EntityOrder | undefined, +) { + return sortField ? [row?.value, row?.entity_id] : [row?.entity_id]; } diff --git a/plugins/catalog-backend/src/service/createRouter.test.ts b/plugins/catalog-backend/src/service/createRouter.test.ts index 6654187526..2d158f7f16 100644 --- a/plugins/catalog-backend/src/service/createRouter.test.ts +++ b/plugins/catalog-backend/src/service/createRouter.test.ts @@ -53,7 +53,7 @@ describe('createRouter readonly disabled', () => { let locationAnalyzer: jest.Mocked; let permissionsService: jest.Mocked; - beforeAll(async () => { + beforeEach(async () => { entitiesCatalog = { entities: jest.fn(), entitiesBatch: jest.fn(), @@ -136,7 +136,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.entities.mockResolvedValueOnce({ - entities: [entities[0]], + entities: { type: 'object', entities: [entities[0]] }, pageInfo: { hasNextPage: false }, }); @@ -146,9 +146,42 @@ describe('createRouter readonly disabled', () => { expect(response.body).toEqual(entities); }); + it('happy path: lists entities when by-entities emulation is enabled', async () => { + const router = await createRouter({ + entitiesCatalog, + locationService, + orchestrator, + logger: mockServices.logger.mock(), + refreshService, + config: new ConfigReader(undefined), + permissionIntegrationRouter: express.Router(), + auth: mockServices.auth(), + httpAuth: mockServices.httpAuth(), + locationAnalyzer, + permissionsService: permissionsService, + disableRelationsCompatibility: true, // added + }); + app = await wrapServer(express().use(router)); + + const entities: Entity[] = [ + { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, + ]; + + entitiesCatalog.queryEntities.mockResolvedValueOnce({ + items: { type: 'object', entities: [entities[0]] }, + pageInfo: {}, + totalItems: 1, + }); + + const response = await request(app).get('/entities'); + + expect(response.status).toEqual(200); + expect(response.body).toEqual(entities); + }); + it('parses single and multiple request parameters and passes them down', async () => { entitiesCatalog.entities.mockResolvedValueOnce({ - entities: [], + entities: { type: 'object', entities: [] }, pageInfo: { hasNextPage: false }, }); const response = await request(app).get( @@ -166,12 +199,58 @@ describe('createRouter readonly disabled', () => { { key: 'b', values: ['3'] }, ], }, - { allOf: [{ key: 'c', values: ['4'] }] }, + { key: 'c', values: ['4'] }, ], }, credentials: mockCredentials.user(), }); }); + + it('parses single and multiple request parameters and passes them down when by-entities emulation is enabled', async () => { + const router = await createRouter({ + entitiesCatalog, + locationService, + orchestrator, + logger: mockServices.logger.mock(), + refreshService, + config: new ConfigReader(undefined), + permissionIntegrationRouter: express.Router(), + auth: mockServices.auth(), + httpAuth: mockServices.httpAuth(), + locationAnalyzer, + permissionsService: permissionsService, + disableRelationsCompatibility: true, // added + }); + app = await wrapServer(express().use(router)); + + entitiesCatalog.queryEntities.mockResolvedValueOnce({ + items: { type: 'object', entities: [] }, + pageInfo: {}, + totalItems: 0, + }); + const response = await request(app).get( + '/entities?filter=a=1,a=2,b=3&filter=c=4', + ); + + expect(response.status).toEqual(200); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.queryEntities).toHaveBeenCalledWith({ + filter: { + anyOf: [ + { + allOf: [ + { key: 'a', values: ['1', '2'] }, + { key: 'b', values: ['3'] }, + ], + }, + { key: 'c', values: ['4'] }, + ], + }, + limit: 10000, + credentials: mockCredentials.user(), + skipTotalItems: true, + }); + }); }); describe('GET /entities/by-query', () => { @@ -181,7 +260,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items, + items: { type: 'object', entities: items }, totalItems: 100, pageInfo: { nextCursor: mockCursor() }, }); @@ -199,7 +278,7 @@ describe('createRouter readonly disabled', () => { it('parses initial request', async () => { entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items: [], + items: { type: 'object', entities: [] }, pageInfo: {}, totalItems: 0, }); @@ -218,7 +297,7 @@ describe('createRouter readonly disabled', () => { { key: 'b', values: ['3'] }, ], }, - { allOf: [{ key: 'c', values: ['4'] }] }, + { key: 'c', values: ['4'] }, ], }, orderFields: [ @@ -235,7 +314,7 @@ describe('createRouter readonly disabled', () => { it('parses encoded params request', async () => { entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items: [], + items: { type: 'object', entities: [] }, pageInfo: {}, totalItems: 0, }); @@ -258,7 +337,7 @@ describe('createRouter readonly disabled', () => { { key: 'b', values: ['3'] }, ], }, - { allOf: [{ key: 'c', values: ['4'] }] }, + { key: 'c', values: ['4'] }, ], }, orderFields: [ @@ -279,7 +358,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items, + items: { type: 'object', entities: items }, totalItems: 100, pageInfo: { nextCursor: mockCursor() }, }); @@ -308,7 +387,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items, + items: { type: 'object', entities: items }, totalItems: 100, pageInfo: { nextCursor: mockCursor({ fullTextFilter: { term: 'mySearch' } }), @@ -350,7 +429,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items, + items: { type: 'object', entities: items }, totalItems: 100, pageInfo: { nextCursor: mockCursor() }, }); @@ -375,7 +454,7 @@ describe('createRouter readonly disabled', () => { ]; entitiesCatalog.queryEntities.mockResolvedValueOnce({ - items, + items: { type: 'object', entities: items }, totalItems: 100, pageInfo: { nextCursor: mockCursor() }, }); @@ -398,7 +477,7 @@ describe('createRouter readonly disabled', () => { }, }; entitiesCatalog.entities.mockResolvedValue({ - entities: [entity], + entities: { type: 'object', entities: [entity] }, pageInfo: { hasNextPage: false }, }); @@ -415,7 +494,7 @@ describe('createRouter readonly disabled', () => { it('responds with a 404 for missing entities', async () => { entitiesCatalog.entities.mockResolvedValue({ - entities: [], + entities: { type: 'object', entities: [] }, pageInfo: { hasNextPage: false }, }); @@ -441,20 +520,15 @@ describe('createRouter readonly disabled', () => { namespace: 'ns', }, }; - entitiesCatalog.entities.mockResolvedValue({ - entities: [entity], - pageInfo: { hasNextPage: false }, + entitiesCatalog.entitiesBatch.mockResolvedValue({ + items: { type: 'object', entities: [entity] }, }); const response = await request(app).get('/entities/by-name/k/ns/n'); - expect(entitiesCatalog.entities).toHaveBeenCalledTimes(1); - expect(entitiesCatalog.entities).toHaveBeenCalledWith({ - filter: basicEntityFilter({ - kind: 'k', - 'metadata.namespace': 'ns', - 'metadata.name': 'n', - }), + expect(entitiesCatalog.entitiesBatch).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.entitiesBatch).toHaveBeenCalledWith({ + entityRefs: ['k:ns/n'], credentials: mockCredentials.user(), }); expect(response.status).toEqual(200); @@ -462,20 +536,15 @@ describe('createRouter readonly disabled', () => { }); it('responds with a 404 for missing entities', async () => { - entitiesCatalog.entities.mockResolvedValue({ - entities: [], - pageInfo: { hasNextPage: false }, + entitiesCatalog.entitiesBatch.mockResolvedValue({ + items: { type: 'object', entities: [null] }, }); const response = await request(app).get('/entities/by-name/b/d/c'); - expect(entitiesCatalog.entities).toHaveBeenCalledTimes(1); - expect(entitiesCatalog.entities).toHaveBeenCalledWith({ - filter: basicEntityFilter({ - kind: 'b', - 'metadata.namespace': 'd', - 'metadata.name': 'c', - }), + expect(entitiesCatalog.entitiesBatch).toHaveBeenCalledTimes(1); + expect(entitiesCatalog.entitiesBatch).toHaveBeenCalledWith({ + entityRefs: ['b:d/c'], credentials: mockCredentials.user(), }); expect(response.status).toEqual(404); @@ -539,7 +608,9 @@ describe('createRouter readonly disabled', () => { }, }; const entityRef = stringifyEntityRef(entity); - entitiesCatalog.entitiesBatch.mockResolvedValue({ items: [entity] }); + entitiesCatalog.entitiesBatch.mockResolvedValue({ + items: { type: 'object', entities: [entity] }, + }); const response = await request(app) .post('/entities/by-refs?filter=kind=Component') .set('Content-Type', 'application/json') @@ -554,13 +625,7 @@ describe('createRouter readonly disabled', () => { entityRefs: [entityRef], fields: expect.any(Function), credentials: mockCredentials.user(), - filter: { - anyOf: [ - { - allOf: [{ key: 'kind', values: ['Component'] }], - }, - ], - }, + filter: { key: 'kind', values: ['Component'] }, }); expect(response.status).toEqual(200); expect(response.body).toEqual({ items: [entity] }); @@ -870,7 +935,7 @@ describe('createRouter readonly disabled', () => { }); }); -describe('createRouter readonly enabled', () => { +describe('createRouter readonly and raw json enabled', () => { let entitiesCatalog: jest.Mocked; let app: express.Express; let locationService: jest.Mocked; @@ -893,6 +958,7 @@ describe('createRouter readonly enabled', () => { getLocationByEntity: jest.fn(), }; const router = await createRouter({ + disableRelationsCompatibility: true, entitiesCatalog, locationService, logger: mockServices.logger.mock(), @@ -919,9 +985,10 @@ describe('createRouter readonly enabled', () => { { apiVersion: 'a', kind: 'b', metadata: { name: 'n' } }, ]; - entitiesCatalog.entities.mockResolvedValueOnce({ - entities: [entities[0]], - pageInfo: { hasNextPage: false }, + entitiesCatalog.queryEntities.mockResolvedValueOnce({ + items: { type: 'raw', entities: [JSON.stringify(entities[0])] }, + pageInfo: {}, + totalItems: 1, }); const response = await request(app).get('/entities'); @@ -1139,7 +1206,7 @@ describe('NextRouter permissioning', () => { }, }; entitiesCatalog.entities.mockResolvedValueOnce({ - entities: [spideySense], + entities: { type: 'object', entities: [spideySense] }, pageInfo: { hasNextPage: false }, }); diff --git a/plugins/catalog-backend/src/service/createRouter.ts b/plugins/catalog-backend/src/service/createRouter.ts index 9b62d1318d..58474f4dbc 100644 --- a/plugins/catalog-backend/src/service/createRouter.ts +++ b/plugins/catalog-backend/src/service/createRouter.ts @@ -23,11 +23,11 @@ import { stringifyEntityRef, } from '@backstage/catalog-model'; import { Config } from '@backstage/config'; -import { InputError, NotFoundError, serializeError } from '@backstage/errors'; +import { InputError, serializeError } from '@backstage/errors'; import express from 'express'; import yn from 'yn'; import { z } from 'zod'; -import { EntitiesCatalog } from '../catalog/types'; +import { Cursor, EntitiesCatalog } from '../catalog/types'; import { CatalogProcessingOrchestrator } from '../processing/types'; import { validateEntityEnvelope } from '../processing/util'; import { @@ -57,6 +57,11 @@ import { } from '@backstage/backend-plugin-api'; import { LocationAnalyzer } from '@backstage/plugin-catalog-node'; import { AuthorizedValidationService } from './AuthorizedValidationService'; +import { + createEntityArrayJsonStream, + writeEntitiesResponse, + writeSingleEntityResponse, +} from './response'; /** * Options used by {@link createRouter}. @@ -77,6 +82,7 @@ export interface RouterOptions { auth: AuthService; httpAuth: HttpAuthService; permissionsService: PermissionsService; + disableRelationsCompatibility?: boolean; } /** @@ -104,6 +110,7 @@ export async function createRouter( permissionsService, auth, httpAuth, + disableRelationsCompatibility = false, } = options; const readonlyEnabled = @@ -135,24 +142,68 @@ export async function createRouter( if (entitiesCatalog) { router .get('/entities', async (req, res) => { - const { entities, pageInfo } = await entitiesCatalog.entities({ - filter: parseEntityFilterParams(req.query), - fields: parseEntityTransformParams(req.query), - order: parseEntityOrderParams(req.query), - pagination: parseEntityPaginationParams(req.query), - credentials: await httpAuth.credentials(req), - }); + const filter = parseEntityFilterParams(req.query); + const fields = parseEntityTransformParams(req.query); + const order = parseEntityOrderParams(req.query); + const pagination = parseEntityPaginationParams(req.query); + const credentials = await httpAuth.credentials(req); - // Add a Link header to the next page - if (pageInfo.hasNextPage) { - const url = new URL(`http://ignored${req.url}`); - url.searchParams.delete('offset'); - url.searchParams.set('after', pageInfo.endCursor); - res.setHeader('link', `<${url.pathname}${url.search}>; rel="next"`); + // When pagination parameters are passed in, use the legacy slow path + // that loads all entities into memory + + if (pagination || disableRelationsCompatibility !== true) { + const { entities, pageInfo } = await entitiesCatalog.entities({ + filter, + fields, + order, + pagination, + credentials, + }); + + // Add a Link header to the next page + if (pageInfo.hasNextPage) { + const url = new URL(`http://ignored${req.url}`); + url.searchParams.delete('offset'); + url.searchParams.set('after', pageInfo.endCursor); + res.setHeader('link', `<${url.pathname}${url.search}>; rel="next"`); + } + + await writeEntitiesResponse(res, entities); + return; } - // TODO(freben): encode the pageInfo in the response - res.json(entities); + const responseStream = createEntityArrayJsonStream(res); + const limit = 10000; + let cursor: Cursor | undefined; + + try { + do { + const result = await entitiesCatalog.queryEntities( + !cursor + ? { + credentials, + fields, + limit, + filter, + orderFields: order, + skipTotalItems: true, + } + : { credentials, fields, limit, cursor }, + ); + + if (result.items.entities.length) { + if (await responseStream.send(result.items)) { + return; // Client closed connection + } + } + + cursor = result.pageInfo?.nextCursor; + } while (cursor); + + responseStream.complete(); + } finally { + responseStream.close(); + } }) .get('/entities/by-query', async (req, res) => { const { items, pageInfo, totalItems } = @@ -163,8 +214,8 @@ export async function createRouter( credentials: await httpAuth.credentials(req), }); - res.json({ - items, + await writeEntitiesResponse(res, items, entities => ({ + items: entities, totalItems, pageInfo: { ...(pageInfo.nextCursor && { @@ -174,7 +225,7 @@ export async function createRouter( prevCursor: encodeCursor(pageInfo.prevCursor), }), }, - }); + })); }) .get('/entities/by-uid/:uid', async (req, res) => { const { uid } = req.params; @@ -182,10 +233,7 @@ export async function createRouter( filter: basicEntityFilter({ 'metadata.uid': uid }), credentials: await httpAuth.credentials(req), }); - if (!entities.length) { - throw new NotFoundError(`No entity with uid ${uid}`); - } - res.status(200).json(entities[0]); + writeSingleEntityResponse(res, entities, `No entity with uid ${uid}`); }) .delete('/entities/by-uid/:uid', async (req, res) => { const { uid } = req.params; @@ -196,20 +244,15 @@ export async function createRouter( }) .get('/entities/by-name/:kind/:namespace/:name', async (req, res) => { const { kind, namespace, name } = req.params; - const { entities } = await entitiesCatalog.entities({ - filter: basicEntityFilter({ - kind: kind, - 'metadata.namespace': namespace, - 'metadata.name': name, - }), + const { items } = await entitiesCatalog.entitiesBatch({ + entityRefs: [stringifyEntityRef({ kind, namespace, name })], credentials: await httpAuth.credentials(req), }); - if (!entities.length) { - throw new NotFoundError( - `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`, - ); - } - res.status(200).json(entities[0]); + writeSingleEntityResponse( + res, + items, + `No entity named '${name}' found, with kind '${kind}' in namespace '${namespace}'`, + ); }) .get( '/entities/by-name/:kind/:namespace/:name/ancestry', @@ -224,13 +267,15 @@ export async function createRouter( ) .post('/entities/by-refs', async (req, res) => { const request = entitiesBatchRequest(req); - const response = await entitiesCatalog.entitiesBatch({ + const { items } = await entitiesCatalog.entitiesBatch({ entityRefs: request.entityRefs, filter: parseEntityFilterParams(req.query), fields: parseEntityTransformParams(req.query, request.fields), credentials: await httpAuth.credentials(req), }); - res.status(200).json(response); + await writeEntitiesResponse(res, items, entities => ({ + items: entities, + })); }) .get('/entity-facets', async (req, res) => { const response = await entitiesCatalog.facets({ diff --git a/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.test.ts b/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.test.ts new file mode 100644 index 0000000000..ea64f5b400 --- /dev/null +++ b/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.test.ts @@ -0,0 +1,196 @@ +/* + * 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 { TestDatabases } from '@backstage/backend-test-utils'; +import { applyEntityFilterToQuery } from './applyEntityFilterToQuery'; +import { + DbFinalEntitiesRow, + DbRefreshStateRow, + DbSearchRow, +} from '../../database/tables'; +import { Knex } from 'knex'; +import { applyDatabaseMigrations } from '../../database/migrations'; +import { EntityFilter } from '@backstage/plugin-catalog-node'; +import { Entity, stringifyEntityRef } from '@backstage/catalog-model'; +import { v4 as uuid } from 'uuid'; +import { buildEntitySearch } from '../../database/operations/stitcher/buildEntitySearch'; + +jest.setTimeout(60_000); + +const databases = TestDatabases.create(); +const strategies = ['in', 'join'] as const; + +describe.each(databases.eachSupportedId())( + 'applyEntityFilterToQuery, %p', + databaseId => { + // #region setup + let knex: Knex; + + beforeAll(async () => { + knex = await databases.init(databaseId); + await applyDatabaseMigrations(knex); + await addEntity({ + apiVersion: 'a', + kind: 'k', + metadata: { name: '1', namespace: 'default' }, + spec: { + foo: 'a', + unique: true, + }, + }); + await addEntity({ + apiVersion: 'a', + kind: 'k', + metadata: { name: '2', namespace: 'default' }, + spec: { + foo: 'a', + }, + }); + await addEntity({ + apiVersion: 'a', + kind: 'k', + metadata: { name: '3', namespace: 'default' }, + spec: { + foo: 'b', + }, + }); + await addEntity({ + apiVersion: 'a', + kind: 'k', + metadata: { name: '4', namespace: 'default' }, + spec: {}, + }); + }); + + afterAll(async () => { + knex.destroy(); + }); + + async function addEntity(entity: Entity) { + const id = uuid(); + const entityRef = stringifyEntityRef(entity); + const entityJson = JSON.stringify(entity); + + await knex('refresh_state').insert({ + entity_id: id, + entity_ref: entityRef, + unprocessed_entity: entityJson, + errors: '[]', + next_update_at: '2031-01-01 23:00:00', + last_discovery_at: '2021-04-01 13:37:00', + }); + + await knex('final_entities').insert({ + entity_id: id, + entity_ref: entityRef, + final_entity: entityJson, + hash: 'h', + stitch_ticket: '', + }); + + const search = await buildEntitySearch(id, entity); + await knex('search').insert(search); + + return id; + } + // #endregion + + describe.each(strategies)('with strategy %p', strategy => { + async function query(filter: EntityFilter): Promise { + const q = + knex('final_entities').whereNotNull( + 'final_entity', + ); + applyEntityFilterToQuery({ + filter: filter, + targetQuery: q, + onEntityIdField: 'final_entities.entity_id', + knex, + strategy, + }); + return await q.then(rows => + rows + .map(row => JSON.parse(row.final_entity!).metadata.name) + .toSorted(), + ); + } + + it('filters correctly', async () => { + await expect(query({ key: 'spec.foo' })).resolves.toEqual([ + '1', + '2', + '3', + ]); + + await expect( + query({ key: 'spec.foo', values: ['a'] }), + ).resolves.toEqual(['1', '2']); + + await expect( + query({ key: 'spec.foo', values: ['b'] }), + ).resolves.toEqual(['3']); + + await expect( + query({ key: 'spec.foo', values: ['a', 'b'] }), + ).resolves.toEqual(['1', '2', '3']); + + await expect( + query({ + anyOf: [ + { key: 'spec.foo', values: ['a'] }, + { key: 'spec.foo', values: ['b'] }, + ], + }), + ).resolves.toEqual(['1', '2', '3']); + + await expect( + query({ not: { key: 'spec.foo', values: ['a'] } }), + ).resolves.toEqual(['3', '4']); + + await expect( + query({ + not: { + anyOf: [ + { key: 'spec.foo', values: ['a'] }, + { key: 'spec.foo', values: ['b'] }, + ], + }, + }), + ).resolves.toEqual(['4']); + + await expect( + query({ + allOf: [ + { key: 'spec.foo' }, + { not: { key: 'spec.foo', values: ['a'] } }, + ], + }), + ).resolves.toEqual(['3']); + + await expect(query({ key: 'spec.unique' })).resolves.toEqual(['1']); + + await expect( + query({ + allOf: [ + { key: 'spec.foo', values: ['a'] }, + { not: { key: 'spec.unique' } }, + ], + }), + ).resolves.toEqual(['2']); + }); + }); + }, +); diff --git a/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.ts b/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.ts new file mode 100644 index 0000000000..b2a7fb6708 --- /dev/null +++ b/plugins/catalog-backend/src/service/request/applyEntityFilterToQuery.ts @@ -0,0 +1,130 @@ +/* + * 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 { + EntitiesSearchFilter, + EntityFilter, +} from '@backstage/plugin-catalog-node'; +import { Knex } from 'knex'; +import { DbSearchRow } from '../../database/tables'; + +function isEntitiesSearchFilter( + filter: EntitiesSearchFilter | EntityFilter, +): filter is EntitiesSearchFilter { + return filter.hasOwnProperty('key'); +} + +function isOrEntityFilter( + filter: EntityFilter, +): filter is { anyOf: EntityFilter[] } { + return filter.hasOwnProperty('anyOf'); +} + +function isNegationEntityFilter( + filter: EntityFilter, +): filter is { not: EntityFilter } { + return filter.hasOwnProperty('not'); +} + +/** + * Applies filtering through a number of WHERE IN subqueries. Example: + * + * ``` + * SELECT * FROM final_entities + * WHERE + * entity_id IN ( + * SELECT entity_id FROM search + * WHERE key = 'kind' AND value = 'component' + * ) + * AND entity_id IN ( + * SELECT entity_id FROM search + * WHERE key = 'spec.lifecycle' AND value = 'production' + * ) + * AND final_entities.final_entity IS NOT NULL + * ``` + * + * This strategy is a good all-rounder, in the sense that it has medium-good + * performance on most queries on all database engines. However, it does not + * scale well down to very short runtimes as well as the JOIN strategy. + */ +function applyInStrategy( + filter: EntityFilter, + targetQuery: Knex.QueryBuilder, + onEntityIdField: string, + knex: Knex, + negate: boolean, +): Knex.QueryBuilder { + if (isNegationEntityFilter(filter)) { + return applyInStrategy( + filter.not, + targetQuery, + onEntityIdField, + knex, + !negate, + ); + } + + if (isEntitiesSearchFilter(filter)) { + const key = filter.key.toLowerCase(); + const values = filter.values?.map(v => v.toLowerCase()); + const matchQuery = knex('search') + .select('search.entity_id') + .where({ key }) + .andWhere(function keyFilter() { + if (values?.length === 1) { + this.where({ value: values.at(0) }); + } else if (values) { + this.andWhere('value', 'in', values); + } + }); + return targetQuery.andWhere( + onEntityIdField, + negate ? 'not in' : 'in', + matchQuery, + ); + } + + return targetQuery[negate ? 'andWhereNot' : 'andWhere']( + function filterFunction() { + if (isOrEntityFilter(filter)) { + for (const subFilter of filter.anyOf ?? []) { + this.orWhere(subQuery => + applyInStrategy(subFilter, subQuery, onEntityIdField, knex, false), + ); + } + } else { + for (const subFilter of filter.allOf ?? []) { + this.andWhere(subQuery => + applyInStrategy(subFilter, subQuery, onEntityIdField, knex, false), + ); + } + } + }, + ); +} + +// The actual exported function +export function applyEntityFilterToQuery(options: { + filter: EntityFilter; + targetQuery: Knex.QueryBuilder; + onEntityIdField: string; + knex: Knex; + strategy?: 'in' | 'join'; +}): Knex.QueryBuilder { + const { filter, targetQuery, onEntityIdField, knex } = options; + + return applyInStrategy(filter, targetQuery, onEntityIdField, knex, false); +} diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts index f9fc596cb9..85e0d9caa1 100644 --- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts +++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.test.ts @@ -27,9 +27,7 @@ describe('parseEntityFilterParams', () => { it('supports single-string format', () => { const result = parseEntityFilterParams({ filter: 'a=1' })!; - expect(result).toEqual({ - anyOf: [{ allOf: [{ key: 'a', values: ['1'] }] }], - }); + expect(result).toEqual({ key: 'a', values: ['1'] }); }); it('supports array-of-strings format', () => { @@ -38,8 +36,8 @@ describe('parseEntityFilterParams', () => { }); expect(result).toEqual({ anyOf: [ - { allOf: [{ key: 'a', values: ['1'] }] }, - { allOf: [{ key: 'b', values: ['2'] }] }, + { key: 'a', values: ['1'] }, + { key: 'b', values: ['2'] }, ], }); }); @@ -50,7 +48,7 @@ describe('parseEntityFilterParams', () => { }); expect(result).toEqual({ anyOf: [ - { allOf: [{ key: 'a', values: ['1'] }] }, + { key: 'a', values: ['1'] }, { allOf: [ { key: 'b', values: ['2', '3'] }, diff --git a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts index 8666712f80..aabb24ff3f 100644 --- a/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts +++ b/plugins/catalog-backend/src/service/request/parseEntityFilterParams.ts @@ -36,12 +36,17 @@ export function parseEntityFilterParams( // Outer array: "any of the inner ones" // Inner arrays: "all of these must match" - const filters = filterStrings.map(parseEntityFilterString).filter(Boolean); + const filters = filterStrings + .map(parseEntityFilterString) + .filter((r): r is EntitiesSearchFilter[] => Boolean(r)); if (!filters.length) { return undefined; } - return { anyOf: filters.map(f => ({ allOf: f! })) }; + const outer = filters.map(inner => + inner.length === 1 ? inner[0] : { allOf: inner }, + ); + return outer.length === 1 ? outer[0] : { anyOf: outer }; } /** diff --git a/plugins/catalog-backend/src/service/response/createEntityArrayJsonStream.ts b/plugins/catalog-backend/src/service/response/createEntityArrayJsonStream.ts new file mode 100644 index 0000000000..5bdc9d8994 --- /dev/null +++ b/plugins/catalog-backend/src/service/response/createEntityArrayJsonStream.ts @@ -0,0 +1,82 @@ +/* + * 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 { EntitiesResponseItems } from '../../catalog/types'; +import { Response } from 'express'; +import { writeResponseData } from './write'; + +export interface EntityArrayJsonStream { + send(entities: EntitiesResponseItems): Promise; + complete(): void; + close(): void; +} + +// Helps stream EntitiesResponseItems[] as a JSON response stream to avoid performance issues +export function createEntityArrayJsonStream( + res: Response, +): EntityArrayJsonStream { + // Imitate the httpRouter behavior of pretty-printing in development + const prettyPrint = process.env.NODE_ENV === 'development'; + let firstSend = true; + let completed = false; + + return { + async send(response) { + if (firstSend) { + res.setHeader('Content-Type', 'application/json; charset=utf-8'); + res.status(200); + res.flushHeaders(); + } + + if (response.type === 'raw') { + for (const item of response.entities) { + const prefix = firstSend ? '[' : ','; + firstSend = false; + + if (await writeResponseData(res, prefix + item)) { + return true; + } + } + return false; + } + + let data: string; + if (prettyPrint) { + data = JSON.stringify(response.entities, null, 2); + data = firstSend ? data.slice(0, -2) : `,\n${data.slice(2, -2)}`; + } else { + data = JSON.stringify(response.entities); + data = firstSend ? data.slice(0, -1) : `,${data.slice(1, -1)}`; + } + + firstSend = false; + return writeResponseData(res, data); + }, + complete() { + if (firstSend) { + res.json([]); + } else { + res.end(prettyPrint ? '\n]' : ']', 'utf8'); + } + completed = true; + }, + close() { + if (!completed) { + res.end(); + } + }, + }; +} diff --git a/plugins/catalog-backend/src/service/response/index.ts b/plugins/catalog-backend/src/service/response/index.ts new file mode 100644 index 0000000000..2e01071dbd --- /dev/null +++ b/plugins/catalog-backend/src/service/response/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +export { + processRawEntitiesResult, + processEntitiesResponseItems, + entitiesResponseToObjects, +} from './process'; +export { writeSingleEntityResponse, writeEntitiesResponse } from './write'; +export { createEntityArrayJsonStream } from './createEntityArrayJsonStream'; diff --git a/plugins/catalog-backend/src/service/response/process.test.ts b/plugins/catalog-backend/src/service/response/process.test.ts new file mode 100644 index 0000000000..60b96608f7 --- /dev/null +++ b/plugins/catalog-backend/src/service/response/process.test.ts @@ -0,0 +1,115 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { + entitiesResponseToObjects, + processEntitiesResponseItems, + processRawEntitiesResult, +} from './process'; + +const mockTransform = (entity: Entity): Entity => ({ + ...entity, + kind: `transformed-${entity.kind}`, +}); + +describe('processRawEntitiesResult', () => { + it('should prefer keeping results in raw form', () => { + expect(processRawEntitiesResult(['{"kind":"test"}', null])).toEqual({ + type: 'raw', + entities: ['{"kind":"test"}', null], + }); + + expect( + processRawEntitiesResult(['{"kind":"test"}', null], mockTransform), + ).toEqual({ + type: 'object', + entities: [{ kind: 'transformed-test' }, null], + }); + }); +}); + +describe('processEntitiesResponseItems', () => { + it('should transform entities in object form', () => { + expect( + processEntitiesResponseItems({ + type: 'object', + entities: [{ kind: 'test' } as Entity, null], + }), + ).toEqual({ + type: 'object', + entities: [{ kind: 'test' }, null], + }); + + expect( + processEntitiesResponseItems( + { + type: 'object', + entities: [{ kind: 'test' } as Entity, null], + }, + mockTransform, + ), + ).toEqual({ + type: 'object', + entities: [{ kind: 'transformed-test' }, null], + }); + }); + + it('should transform entities in raw form', () => { + expect( + processEntitiesResponseItems({ + type: 'raw', + entities: ['{"kind":"test"}', null], + }), + ).toEqual({ + type: 'raw', + entities: ['{"kind":"test"}', null], + }); + + expect( + processEntitiesResponseItems( + { + type: 'raw', + entities: ['{"kind":"test"}', null], + }, + mockTransform, + ), + ).toEqual({ + type: 'object', + entities: [{ kind: 'transformed-test' }, null], + }); + }); +}); + +describe('entitiesResponseToObjects', () => { + it('should convert entities in object form', () => { + expect( + entitiesResponseToObjects({ + type: 'object', + entities: [null, { kind: 'test' } as Entity], + }), + ).toEqual([null, { kind: 'test' }]); + }); + + it('should convert entities in raw form', () => { + expect( + entitiesResponseToObjects({ + type: 'raw', + entities: [null, '{"kind":"test"}'], + }), + ).toEqual([null, { kind: 'test' }]); + }); +}); diff --git a/plugins/catalog-backend/src/service/response/process.ts b/plugins/catalog-backend/src/service/response/process.ts new file mode 100644 index 0000000000..fa07063f5b --- /dev/null +++ b/plugins/catalog-backend/src/service/response/process.ts @@ -0,0 +1,62 @@ +/* + * 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 { Entity } from '@backstage/catalog-model'; +import { EntitiesResponseItems } from '../../catalog/types'; + +export function processRawEntitiesResult( + serializedEntities: (string | null)[], + transform?: (entity: Entity) => Entity, +): EntitiesResponseItems { + if (transform) { + return { + type: 'object', + entities: serializedEntities.map(e => + e !== null ? transform(JSON.parse(e)) : e, + ), + }; + } + + return { + type: 'raw', + entities: serializedEntities, + }; +} + +export function processEntitiesResponseItems( + response: EntitiesResponseItems, + transform?: (entity: Entity) => Entity, +): EntitiesResponseItems { + if (!transform) { + return response; + } + if (response.type === 'raw') { + return processRawEntitiesResult(response.entities, transform); + } + return { + type: 'object', + entities: response.entities.map(e => (e !== null ? transform(e) : e)), + }; +} + +export function entitiesResponseToObjects( + response: EntitiesResponseItems, +): (Entity | null)[] { + if (response.type === 'object') { + return response.entities; + } + return response.entities.map(e => (e !== null ? JSON.parse(e) : e)); +} diff --git a/plugins/catalog-backend/src/service/response/write.test.ts b/plugins/catalog-backend/src/service/response/write.test.ts new file mode 100644 index 0000000000..fdca874904 --- /dev/null +++ b/plugins/catalog-backend/src/service/response/write.test.ts @@ -0,0 +1,317 @@ +/* + * 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 express from 'express'; +import { mockErrorHandler } from '@backstage/backend-test-utils'; +import request from 'supertest'; +import { writeEntitiesResponse, writeSingleEntityResponse } from './write'; + +describe('writeSingleEntityResponse', () => { + const app = express(); + app.use(express.json()); + app.get('/echo', (req, res) => { + writeSingleEntityResponse(res, req.body, 'not found'); + }); + app.use(mockErrorHandler()); + + describe('in object form', () => { + it('should write a single entity', async () => { + const res = await request(app) + .get('/echo') + .send({ + type: 'object', + entities: [{ kind: 'Component' }, { kind: 'User' }], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ kind: 'Component' }); + }); + + it('should write a missing entity', async () => { + const res = await request(app) + .get('/echo') + .send({ type: 'object', entities: [null] }); + + expect(res.status).toBe(404); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toMatchObject({ + error: { name: 'NotFoundError', message: 'not found' }, + }); + }); + + it('should write no entities', async () => { + const res = await request(app) + .get('/echo') + .send({ type: 'object', entities: [] }); + + expect(res.status).toBe(404); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toMatchObject({ + error: { name: 'NotFoundError', message: 'not found' }, + }); + }); + }); + + describe('in raw form', () => { + it('should write a single entity', async () => { + const res = await request(app) + .get('/echo') + .send({ + type: 'raw', + entities: ['{"kind":"Component"}', '{"kind":"User"}'], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ kind: 'Component' }); + }); + + it('should write a missing entity', async () => { + const res = await request(app) + .get('/echo') + .send({ type: 'raw', entities: [null] }); + + expect(res.status).toBe(404); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toMatchObject({ + error: { name: 'NotFoundError', message: 'not found' }, + }); + }); + + it('should write no entities', async () => { + const res = await request(app) + .get('/echo') + .send({ type: 'raw', entities: [] }); + + expect(res.status).toBe(404); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toMatchObject({ + error: { name: 'NotFoundError', message: 'not found' }, + }); + }); + }); +}); + +describe('writeEntitiesResponse', () => { + const app = express(); + app.use(express.json()); + app.get('/echo', (req, res) => { + writeEntitiesResponse(res, req.body); + }); + app.get('/wrapped', (req, res) => { + writeEntitiesResponse(res, req.body, entities => ({ + page: 1, + items: entities, + totalItems: 1337, + })); + }); + app.use(mockErrorHandler()); + + describe('in object form', () => { + it('should return empty list', async () => { + const res = await request(app).get('/echo').send({ + type: 'object', + entities: [], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual([]); + }); + + it('should return mixed objects', async () => { + const res = await request(app) + .get('/echo') + .send({ + type: 'object', + entities: [{ kind: 'Component' }, null, { kind: 'User' }, null], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual([ + { kind: 'Component' }, + null, + { kind: 'User' }, + null, + ]); + }); + + it('should wrap response of empty list', async () => { + const res = await request(app) + .get('/wrapped') + .send({ type: 'object', entities: [] }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ page: 1, items: [], totalItems: 1337 }); + }); + + it('should wrap response of mixed list', async () => { + const res = await request(app) + .get('/wrapped') + .send({ + type: 'object', + entities: [{ kind: 'Component' }, null, { kind: 'User' }, null], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ + page: 1, + items: [{ kind: 'Component' }, null, { kind: 'User' }, null], + totalItems: 1337, + }); + }); + }); + + describe('in raw form', () => { + it('should return empty list', async () => { + const res = await request(app).get('/echo').send({ + type: 'raw', + entities: [], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual([]); + }); + + it('should return mixed objects', async () => { + const res = await request(app) + .get('/echo') + .send({ + type: 'raw', + entities: ['{"kind":"Component"}', null, '{"kind":"User"}', null], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual([ + { kind: 'Component' }, + null, + { kind: 'User' }, + null, + ]); + }); + + it('should wrap response of empty list', async () => { + const res = await request(app) + .get('/wrapped') + .send({ type: 'raw', entities: [] }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ page: 1, items: [], totalItems: 1337 }); + }); + + it('should wrap response of mixed list', async () => { + const res = await request(app) + .get('/wrapped') + .send({ + type: 'raw', + entities: ['{"kind":"Component"}', null, '{"kind":"User"}', null], + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ + page: 1, + items: [{ kind: 'Component' }, null, { kind: 'User' }, null], + totalItems: 1337, + }); + }); + + it('should write a large wrapped response', async () => { + const entityMock = JSON.stringify({ + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'my-component', + namespace: 'default', + annotations: { + 'backstage.io/managed-by-location': 'url:https://example.com', + }, + }, + spec: { + type: 'service', + owner: 'me', + lifecycle: 'production', + }, + }); + const res = await request(app) + .get('/wrapped') + .send({ + type: 'raw', + entities: Array(300).fill(entityMock), + }); + + expect(res.status).toBe(200); + expect(res.type).toBe('application/json'); + expect(res.header['content-type']).toBe( + 'application/json; charset=utf-8', + ); + expect(res.body).toEqual({ + page: 1, + items: expect.objectContaining({ length: 300 }), + totalItems: 1337, + }); + }); + }); +}); diff --git a/plugins/catalog-backend/src/service/response/write.ts b/plugins/catalog-backend/src/service/response/write.ts new file mode 100644 index 0000000000..b313e3a630 --- /dev/null +++ b/plugins/catalog-backend/src/service/response/write.ts @@ -0,0 +1,117 @@ +/* + * 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 { Response } from 'express'; +import { EntitiesResponseItems } from '../../catalog/types'; +import { JsonValue } from '@backstage/types'; +import { NotFoundError } from '@backstage/errors'; + +const JSON_CONTENT_TYPE = 'application/json; charset=utf-8'; + +export function writeSingleEntityResponse( + res: Response, + response: EntitiesResponseItems, + notFoundMessage: string, +) { + if (response.type === 'object') { + if (!response.entities[0]) { + throw new NotFoundError(notFoundMessage); + } + + res.json(response.entities[0]); + } else { + if (!response.entities[0]) { + throw new NotFoundError(notFoundMessage); + } + + res.setHeader('Content-Type', JSON_CONTENT_TYPE); + res.end(response.entities[0]); + } +} + +export async function writeEntitiesResponse( + res: Response, + response: EntitiesResponseItems, + responseWrapper?: (entities: JsonValue) => JsonValue, +) { + if (response.type === 'object') { + res.json( + responseWrapper + ? responseWrapper?.(response.entities) + : response.entities, + ); + return; + } + + res.setHeader('Content-Type', JSON_CONTENT_TYPE); + + // responseWrapper allows the caller to render the entities within an object + let trailing = ''; + if (responseWrapper) { + const marker = `__MARKER_${Math.random().toString(36).slice(2, 10)}__`; + const wrapped = JSON.stringify(responseWrapper(marker)); + const parts = wrapped.split(`"${marker}"`); + if (parts.length !== 2) { + throw new Error( + `Entity items response was incorrectly wrapped into ${parts.length} different parts`, + ); + } + res.write(parts[0], 'utf8'); + trailing = parts[1]; + } + + let first = true; + for (const entity of response.entities) { + const prefix = first ? '[' : ','; + first = false; + + if (await writeResponseData(res, prefix + entity)) { + return; + } + } + res.end(`${first ? '[' : ''}]${trailing}`); +} + +/** + * Writes a data to the response and waits if the response buffer needs draining. + * + * @internal + * @returns true if the response was closed while waiting for the buffer to drain + */ +export async function writeResponseData(res: Response, data: string | Buffer) { + const ok = res.write(data, 'utf8'); + if (!ok) { + if (res.closed) { + return true; + } + const closed = await new Promise(resolve => { + function onContinue() { + res.off('drain', onContinue); + res.off('close', onClose); + resolve(false); + } + function onClose() { + res.off('drain', onContinue); + res.off('close', onClose); + resolve(true); + } + res.on('drain', onContinue); + res.on('close', onClose); + }); + return closed; + } + return false; +} diff --git a/plugins/catalog-backend/src/service/util.ts b/plugins/catalog-backend/src/service/util.ts index 4b041d1a70..9847cb7225 100644 --- a/plugins/catalog-backend/src/service/util.ts +++ b/plugins/catalog-backend/src/service/util.ts @@ -25,6 +25,11 @@ import { QueryEntitiesRequest, } from '../catalog/types'; import { EntityFilter } from '@backstage/plugin-catalog-node'; +import { + Entity, + parseEntityRef, + stringifyEntityRef, +} from '@backstage/catalog-model'; export async function requireRequestBody(req: Request): Promise { const contentType = req.header('content-type'); @@ -138,3 +143,26 @@ export function decodeCursor(encodedCursor: string) { throw new InputError(`Malformed cursor: ${e}`); } } + +// TODO(freben): This is added as a compatibility guarantee, until we can be +// sure that all adopters have re-stitched their entities so that the new +// targetRef field is present on them, and that they have stopped consuming +// the now-removed old field +// TODO(patriko): Remove this in catalog 2.0 +export function expandLegacyCompoundRelationsInEntity(entity: Entity): Entity { + if (entity.relations) { + for (const relation of entity.relations as any) { + if (!relation.targetRef && relation.target) { + // This is the case where an old-form entity, not yet stitched with + // the updated code, was in the database + relation.targetRef = stringifyEntityRef(relation.target); + } else if (!relation.target && relation.targetRef) { + // This is the case where a new-form entity, stitched with the + // updated code, was in the database but we still want to produce + // the old data shape as well for compatibility reasons + relation.target = parseEntityRef(relation.targetRef); + } + } + } + return entity; +} diff --git a/plugins/catalog-backend/src/stitching/progressTracker.ts b/plugins/catalog-backend/src/stitching/progressTracker.ts index 8c305b4978..9e00a1a01b 100644 --- a/plugins/catalog-backend/src/stitching/progressTracker.ts +++ b/plugins/catalog-backend/src/stitching/progressTracker.ts @@ -54,8 +54,7 @@ export function progressTracker(knex: Knex, logger: LoggerService) { stitchingQueueCount.addCallback(async result => { const total = await knex('refresh_state') .count({ count: '*' }) - .whereNotNull('next_stitch_at') - .where('next_stitch_at', '<=', knex.fn.now()); + .whereNotNull('next_stitch_at'); result.observe(Number(total[0].count)); }); diff --git a/plugins/catalog-backend/src/stitching/types.ts b/plugins/catalog-backend/src/stitching/types.ts index 7064dd1a1c..bbb6223968 100644 --- a/plugins/catalog-backend/src/stitching/types.ts +++ b/plugins/catalog-backend/src/stitching/types.ts @@ -70,15 +70,12 @@ export function stitchingStrategyFromConfig(config: Config): StitchingStrategy { const stitchTimeoutKey = 'catalog.stitchingStrategy.stitchTimeout'; const pollingInterval = config.has(pollingIntervalKey) - ? readDurationFromConfig(config, { - key: pollingIntervalKey, - }) + ? readDurationFromConfig(config, { key: pollingIntervalKey }) : { seconds: 1 }; const stitchTimeout = config.has(stitchTimeoutKey) - ? readDurationFromConfig(config, { - key: stitchTimeoutKey, - }) + ? readDurationFromConfig(config, { key: stitchTimeoutKey }) : { seconds: 60 }; + return { mode: 'deferred', pollingInterval: pollingInterval, diff --git a/plugins/catalog-backend/src/tests/integration.test.ts b/plugins/catalog-backend/src/tests/integration.test.ts index d278fb4f0a..e85ebe48ce 100644 --- a/plugins/catalog-backend/src/tests/integration.test.ts +++ b/plugins/catalog-backend/src/tests/integration.test.ts @@ -30,7 +30,6 @@ import { processingResult, } from '@backstage/plugin-catalog-node'; import { PermissionEvaluator } from '@backstage/plugin-permission-common'; -import { JsonObject } from '@backstage/types'; import { createHash } from 'crypto'; import { Knex } from 'knex'; import { EntitiesCatalog } from '../catalog/types'; @@ -55,6 +54,7 @@ import { DefaultStitcher } from '../stitching/DefaultStitcher'; import { mockServices } from '@backstage/backend-test-utils'; import { LoggerService } from '@backstage/backend-plugin-api'; import { DatabaseManager } from '@backstage/backend-common'; +import { entitiesResponseToObjects } from '../service/response'; const voidLogger = mockServices.logger.mock(); @@ -198,7 +198,7 @@ class TestHarness { readonly #proxyProgressTracker: ProxyProgressTracker; static async create(options?: { - config?: JsonObject; + disableRelationsCompatibility?: boolean; logger?: LoggerService; db?: Knex; permissions?: PermissionEvaluator; @@ -208,21 +208,19 @@ class TestHarness { emit: CatalogProcessorEmit, ): Promise; }) { - const config = new ConfigReader( - options?.config ?? { - backend: { - database: { - client: 'better-sqlite3', - connection: ':memory:', - }, - }, - catalog: { - stitchingStrategy: { - mode: 'immediate', - }, + const config = new ConfigReader({ + backend: { + database: { + client: 'better-sqlite3', + connection: ':memory:', }, }, - ); + catalog: { + stitchingStrategy: { + mode: 'immediate', + }, + }, + }); const logger = options?.logger ?? mockServices.logger.mock(); const db = options?.db ?? @@ -279,6 +277,7 @@ class TestHarness { database: db, logger, stitcher, + disableRelationsCompatibility: options?.disableRelationsCompatibility, }); const proxyProgressTracker = new ProxyProgressTracker( new NoopProgressTracker(), @@ -365,7 +364,12 @@ class TestHarness { async getOutputEntities(): Promise> { const { entities } = await this.#catalog.entities(); - return Object.fromEntries(entities.map(e => [stringifyEntityRef(e), e])); + return Object.fromEntries( + entitiesResponseToObjects(entities).map(e => [ + stringifyEntityRef(e!), + e!, + ]), + ); } async refresh(options: RefreshOptions) { @@ -442,7 +446,6 @@ describe('Catalog Backend Integration', () => { cause: { name: 'Error', message: 'NOPE', - stack: expect.stringMatching(/^Error: NOPE/), }, }, }, @@ -782,4 +785,57 @@ describe('Catalog Backend Integration', () => { ], }); }); + + it('should return valid responses in raw JSON mode', async () => { + const harness = await TestHarness.create({ + disableRelationsCompatibility: true, + }); + + const entityA = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'a', + annotations: { + 'backstage.io/managed-by-location': 'url:.', + 'backstage.io/managed-by-origin-location': 'url:.', + }, + }, + }; + const entityB = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: 'b', + annotations: { + 'backstage.io/managed-by-location': 'url:.', + 'backstage.io/managed-by-origin-location': 'url:.', + }, + }, + }; + + await harness.setInputEntities([entityA, entityB]); + await expect(harness.process()).resolves.toEqual({}); + + await expect(harness.getOutputEntities()).resolves.toEqual({ + 'component:default/a': { + ...entityA, + metadata: { + ...entityA.metadata, + etag: expect.any(String), + uid: expect.any(String), + }, + relations: [], + }, + 'component:default/b': { + ...entityB, + metadata: { + ...entityB.metadata, + etag: expect.any(String), + uid: expect.any(String), + }, + relations: [], + }, + }); + }); }); diff --git a/plugins/catalog-backend/src/tests/performance/providerDeltaMutations.test.ts b/plugins/catalog-backend/src/tests/performance/providerDeltaMutations.test.ts new file mode 100644 index 0000000000..6e95c2535a --- /dev/null +++ b/plugins/catalog-backend/src/tests/performance/providerDeltaMutations.test.ts @@ -0,0 +1,115 @@ +/* + * 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 { TestDatabases, mockServices } from '@backstage/backend-test-utils'; +import { Knex } from 'knex'; +import { applyDatabaseMigrations } from '../../database/migrations'; +import { describePerformanceTest, performanceTraceEnabled } from './lib/env'; +import { DefaultProviderDatabase } from '../../database/DefaultProviderDatabase'; +import { DeferredEntity } from '@backstage/plugin-catalog-node'; + +// #region Helpers + +jest.setTimeout(600_000); + +const databases = TestDatabases.create({ + ids: [/* 'MYSQL_8', */ 'POSTGRES_16', /* 'POSTGRES_12',*/ 'SQLITE_3'], + disableDocker: false, +}); + +const traceLog: typeof console.log = performanceTraceEnabled + ? console.log + : () => {}; + +// #endregion +// #region Tests + +describePerformanceTest('providerDeltaMutations', () => { + let knex: Knex; + + describe.each(databases.eachSupportedId())('%p', databaseId => { + beforeAll(async () => { + knex = await databases.init(databaseId); + await applyDatabaseMigrations(knex); + }); + + afterAll(async () => { + await knex.destroy(); + }); + + it.each([200, 50_000])( + 'inserts and then overwrites identical sets using delta mutations, batch size %p', + async batchSize => { + const sut = new DefaultProviderDatabase({ + database: knex, + logger: mockServices.logger.mock(), + }); + + const sourceKey = 'source-key'; + const entities: DeferredEntity[] = Array.from( + { length: batchSize }, + (_, i) => ({ + entity: { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', + metadata: { + name: `component-${i}`, + namespace: 'default', + }, + spec: { + type: 'service', + lifecycle: 'production', + }, + }, + }), + ); + + let start = Date.now(); + await sut.replaceUnprocessedEntities(knex, { + type: 'delta', + sourceKey, + added: entities, + removed: [], + }); + let perSecond = Math.round(batchSize / ((Date.now() - start) / 1000)); + traceLog( + `${databaseId} inserted ${perSecond} entities per second at a batch size of ${batchSize}`, + ); + + start = Date.now(); + const rounds = 20; + for (let i = 0; i < rounds; i++) { + await sut.replaceUnprocessedEntities(knex, { + type: 'delta', + sourceKey, + added: entities, + removed: [], + }); + } + perSecond = Math.round( + (batchSize * rounds) / ((Date.now() - start) / 1000), + ); + traceLog( + `${databaseId} updated ${perSecond} entities per second at a batch size of ${batchSize}`, + ); + + expect(true).toBe(true); + }, + ); + }); +}); + +// #endregion diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index e1657111e7..a4d843649e 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -221,7 +221,7 @@ describePerformanceTest('stitchingPerformance', () => { const backend = await startTestBackend({ features: [ - import('@backstage/plugin-catalog-backend/alpha'), + import('@backstage/plugin-catalog-backend'), mockServices.rootConfig.factory({ data: config }), mockServices.database.factory({ knex }), createBackendModule({ diff --git a/plugins/catalog-common/CHANGELOG.md b/plugins/catalog-common/CHANGELOG.md index ca71821feb..21f0f63e42 100644 --- a/plugins/catalog-common/CHANGELOG.md +++ b/plugins/catalog-common/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-catalog-common +## 1.1.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 1.1.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-search-common@1.2.15 + ## 1.1.0 ### Minor Changes diff --git a/plugins/catalog-common/package.json b/plugins/catalog-common/package.json index 6e69dd0ef8..c7ba0aba6e 100644 --- a/plugins/catalog-common/package.json +++ b/plugins/catalog-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-common", - "version": "1.1.0", + "version": "1.1.2-next.0", "description": "Common functionalities for the catalog plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-graph/CHANGELOG.md b/plugins/catalog-graph/CHANGELOG.md index 0c4021d4bf..90cb575797 100644 --- a/plugins/catalog-graph/CHANGELOG.md +++ b/plugins/catalog-graph/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-catalog-graph +## 0.4.14-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + +## 0.4.14-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + +## 0.4.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + +## 0.4.12 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + ## 0.4.12-next.3 ### Patch Changes diff --git a/plugins/catalog-graph/README.md b/plugins/catalog-graph/README.md index 0862abbc96..b9400e8e8b 100644 --- a/plugins/catalog-graph/README.md +++ b/plugins/catalog-graph/README.md @@ -137,6 +137,20 @@ return ( ); ``` +Once you have your custom implementation, you can follow these steps to modify the required components: + +- In the `app.tsx` update the `CatalogGraphPage` component to include your custom styles: + +```tsx +} /> +``` + +- In the `Entity.tsx` file, update the `EntityCatalogGraphCard` component to this: + +```tsx + +``` + ## Development Run `yarn` in the root of this plugin to install all dependencies and then `yarn start` to run a [development version](./dev/index.tsx) of this plugin. diff --git a/plugins/catalog-graph/package.json b/plugins/catalog-graph/package.json index 13bd95ab61..aa7649e01f 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.12-next.3", + "version": "0.4.14-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-graph", diff --git a/plugins/catalog-import/CHANGELOG.md b/plugins/catalog-import/CHANGELOG.md index 393e313e63..323aaa0803 100644 --- a/plugins/catalog-import/CHANGELOG.md +++ b/plugins/catalog-import/CHANGELOG.md @@ -1,5 +1,78 @@ # @backstage/plugin-catalog-import +## 0.12.8-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.12.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.12.8-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.12.6 + +### Patch Changes + +- ea5b7f3: Fixed parsing of catalog-info.yaml when creating a PR to register a repository if the file contains more than one document +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.12.6-next.3 ### Patch Changes diff --git a/plugins/catalog-import/package.json b/plugins/catalog-import/package.json index 3f06e98609..42929d872d 100644 --- a/plugins/catalog-import/package.json +++ b/plugins/catalog-import/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-import", - "version": "0.12.6-next.3", + "version": "0.12.8-next.2", "description": "A Backstage plugin the helps you import entities into your catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog-import/report-alpha.api.md b/plugins/catalog-import/report-alpha.api.md index 1706404b94..c13f7a1a4a 100644 --- a/plugins/catalog-import/report-alpha.api.md +++ b/plugins/catalog-import/report-alpha.api.md @@ -18,21 +18,6 @@ const _default: FrontendPlugin< }, {}, { - 'api:catalog-import': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'page:catalog-import': ExtensionDefinition<{ kind: 'page'; name: undefined; @@ -63,6 +48,21 @@ const _default: FrontendPlugin< routeRef?: RouteRef | undefined; }; }>; + 'api:catalog-import': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; } >; export default _default; diff --git a/plugins/catalog-node/CHANGELOG.md b/plugins/catalog-node/CHANGELOG.md index e4e05ee019..a0c09fdc48 100644 --- a/plugins/catalog-node/CHANGELOG.md +++ b/plugins/catalog-node/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-catalog-node +## 1.15.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.15.0-next.1 + +### Minor Changes + +- 8edc4cd: Updated the `catalogServiceMock` return type to match both `CatalogService` and `CatalogApi` + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + +## 1.14.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 1.14.0 + +### Minor Changes + +- bc13b42: The `catalogServiceRef` now has its own accompanying `CatalogService` interface that requires Backstage `credentials` objects to be passed. This new version of the `catalogServiceRef` has been promoted and is now available via the main `@backstage/plugin-catalog-node` entry point. + + The old `catalogServiceRef` with the old `CatalogApi` type is still available from the `/alpha` entry point. + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-node@0.8.5 + ## 1.14.0-next.2 ### Patch Changes diff --git a/plugins/catalog-node/package.json b/plugins/catalog-node/package.json index 2e0c7bdf4f..fbcdc1d95a 100644 --- a/plugins/catalog-node/package.json +++ b/plugins/catalog-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-node", - "version": "1.14.0-next.2", + "version": "1.15.0-next.2", "description": "The plugin-catalog-node module for @backstage/plugin-catalog-backend", "backstage": { "role": "node-library", diff --git a/plugins/catalog-node/report-testUtils.api.md b/plugins/catalog-node/report-testUtils.api.md index ec50d835be..35dee113c0 100644 --- a/plugins/catalog-node/report-testUtils.api.md +++ b/plugins/catalog-node/report-testUtils.api.md @@ -3,23 +3,116 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AddLocationRequest } from '@backstage/catalog-client'; +import { AddLocationResponse } from '@backstage/catalog-client'; import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogRequestOptions } from '@backstage/catalog-client'; +import { CatalogService } from '@backstage/plugin-catalog-node'; +import { CatalogServiceRequestOptions } from '@backstage/plugin-catalog-node'; +import { CompoundEntityRef } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; +import { GetEntitiesByRefsRequest } from '@backstage/catalog-client'; +import { GetEntitiesByRefsResponse } from '@backstage/catalog-client'; +import { GetEntitiesRequest } from '@backstage/catalog-client'; +import { GetEntitiesResponse } from '@backstage/catalog-client'; +import { GetEntityAncestorsRequest } from '@backstage/catalog-client'; +import { GetEntityAncestorsResponse } from '@backstage/catalog-client'; +import { GetEntityFacetsRequest } from '@backstage/catalog-client'; +import { GetEntityFacetsResponse } from '@backstage/catalog-client'; +import { Location as Location_2 } from '@backstage/catalog-client'; +import { QueryEntitiesRequest } from '@backstage/catalog-client'; +import { QueryEntitiesResponse } from '@backstage/catalog-client'; import { ServiceFactory } from '@backstage/backend-plugin-api'; import { ServiceMock } from '@backstage/backend-test-utils'; +import { ValidateEntityResponse } from '@backstage/catalog-client'; + +// @public +export interface CatalogServiceMock extends CatalogService, CatalogApi { + // (undocumented) + addLocation( + location: AddLocationRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getEntities( + request?: GetEntitiesRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getEntitiesByRefs( + request: GetEntitiesByRefsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getEntityAncestors( + request: GetEntityAncestorsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getEntityByRef( + entityRef: string | CompoundEntityRef, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getEntityFacets( + request: GetEntityFacetsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getLocationByEntity( + entityRef: string | CompoundEntityRef, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getLocationById( + id: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + getLocationByRef( + locationRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + queryEntities( + request?: QueryEntitiesRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + refreshEntity( + entityRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + removeEntityByUid( + uid: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + removeLocationById( + id: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + // (undocumented) + validateEntity( + entity: Entity, + locationRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; +} // @public export function catalogServiceMock(options?: { entities?: Entity[]; -}): CatalogApi; +}): CatalogServiceMock; // @public export namespace catalogServiceMock { const factory: (options?: { entities?: Entity[]; - }) => ServiceFactory; + }) => ServiceFactory; const mock: ( - partialImpl?: Partial | undefined, - ) => ServiceMock; + partialImpl?: Partial | undefined, + ) => ServiceMock; } ``` diff --git a/plugins/catalog-node/src/testUtils.ts b/plugins/catalog-node/src/testUtils.ts index fd1134daf4..6719d77146 100644 --- a/plugins/catalog-node/src/testUtils.ts +++ b/plugins/catalog-node/src/testUtils.ts @@ -21,3 +21,4 @@ */ export { catalogServiceMock } from './testUtils/catalogServiceMock'; +export type { CatalogServiceMock } from './testUtils/types'; diff --git a/plugins/catalog-node/src/testUtils/catalogServiceMock.ts b/plugins/catalog-node/src/testUtils/catalogServiceMock.ts index b9988572ac..2e8a772dc3 100644 --- a/plugins/catalog-node/src/testUtils/catalogServiceMock.ts +++ b/plugins/catalog-node/src/testUtils/catalogServiceMock.ts @@ -15,15 +15,16 @@ */ import { + ServiceFactory, ServiceRef, createServiceFactory, } from '@backstage/backend-plugin-api'; import { InMemoryCatalogClient } from '@backstage/catalog-client/testUtils'; import { Entity } from '@backstage/catalog-model'; -import { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha'; +import { catalogServiceRef } from '@backstage/plugin-catalog-node'; // eslint-disable-next-line @backstage/no-undeclared-imports import { ServiceMock } from '@backstage/backend-test-utils'; -import { CatalogApi } from '@backstage/catalog-client'; +import { CatalogServiceMock } from './types'; /** @internal */ function simpleMock( @@ -60,7 +61,7 @@ function simpleMock( */ export function catalogServiceMock(options?: { entities?: Entity[]; -}): CatalogApi { +}): CatalogServiceMock { return new InMemoryCatalogClient(options); } @@ -80,12 +81,12 @@ export namespace catalogServiceMock { service: catalogServiceRef, deps: {}, factory: () => new InMemoryCatalogClient(options), - }); + }) as ServiceFactory; /** * Creates a catalog client whose methods are mock functions, possibly with * some of them overloaded by the caller. */ - export const mock = simpleMock(catalogServiceRef, () => ({ + export const mock = simpleMock(catalogServiceRef, () => ({ getEntities: jest.fn(), getEntitiesByRefs: jest.fn(), queryEntities: jest.fn(), diff --git a/plugins/catalog-node/src/testUtils/types.ts b/plugins/catalog-node/src/testUtils/types.ts new file mode 100644 index 0000000000..1fbbec98f1 --- /dev/null +++ b/plugins/catalog-node/src/testUtils/types.ts @@ -0,0 +1,123 @@ +/* + * 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 { + AddLocationRequest, + AddLocationResponse, + CatalogApi, + CatalogRequestOptions, + GetEntitiesByRefsRequest, + GetEntitiesByRefsResponse, + GetEntitiesRequest, + GetEntitiesResponse, + GetEntityAncestorsRequest, + GetEntityAncestorsResponse, + GetEntityFacetsRequest, + GetEntityFacetsResponse, + Location, + QueryEntitiesRequest, + QueryEntitiesResponse, + ValidateEntityResponse, +} from '@backstage/catalog-client'; +import { CompoundEntityRef, Entity } from '@backstage/catalog-model'; +import { + CatalogService, + CatalogServiceRequestOptions, +} from '@backstage/plugin-catalog-node'; + +/** + * A mock friendly version of `CatalogService` / + * {@link @backstage/catalog-client#CatalogApi | CatalogApi}. + * + * @public + * @remarks + * + * This interface supports both API types at the same time, and has an optional + * second argument to simplify testing since the mock implementation does not + * care about credentials. + */ +export interface CatalogServiceMock extends CatalogService, CatalogApi { + getEntities( + request?: GetEntitiesRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getEntitiesByRefs( + request: GetEntitiesByRefsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + queryEntities( + request?: QueryEntitiesRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getEntityAncestors( + request: GetEntityAncestorsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getEntityByRef( + entityRef: string | CompoundEntityRef, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + removeEntityByUid( + uid: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + refreshEntity( + entityRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getEntityFacets( + request: GetEntityFacetsRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getLocationById( + id: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getLocationByRef( + locationRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + addLocation( + location: AddLocationRequest, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + removeLocationById( + id: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + getLocationByEntity( + entityRef: string | CompoundEntityRef, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; + + validateEntity( + entity: Entity, + locationRef: string, + options?: CatalogServiceRequestOptions | CatalogRequestOptions, + ): Promise; +} diff --git a/plugins/catalog-react/CHANGELOG.md b/plugins/catalog-react/CHANGELOG.md index fa110af43f..15f549c248 100644 --- a/plugins/catalog-react/CHANGELOG.md +++ b/plugins/catalog-react/CHANGELOG.md @@ -1,5 +1,92 @@ # @backstage/plugin-catalog-react +## 1.14.3-next.2 + +### Patch Changes + +- 95092a6: Fixed an issue where `` would re-render its children on page load for smaller screens, potentially leading to unnecessary additional backend requests. +- 4a43398: Fixed an issue where the `EntityOwnerPicker` component failed to load when the `mode` prop was set to `owners-only`. In this mode, the `EntityOwnerPicker` does not load details about the owners, such as `displayName` or `title`. To display these details, use `mode=all` instead. +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/frontend-test-utils@0.2.4-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 1.14.3-next.1 + +### Patch Changes + +- d97a2cd: Fixed an issue causing the `EntityOwnerPicker` to reset scrolling when more elements are loaded. +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/frontend-test-utils@0.2.4-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## 1.14.3-next.0 + +### Patch Changes + +- f18c67d: Fix catalog filtering to allow searching entities by display name +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-test-utils@0.2.4-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-react@0.4.28 + +## 1.14.1 + +### Patch Changes + +- 9cc82c0: Fixed bug in `EntityDisplayName` where text was overflowing. +- 6fcbb3b: Ensure EntityDisplayName component link receives underline on hover. +- 9670906: Improve UI consistency of default catalog filters +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/frontend-test-utils@0.2.2 + - @backstage/integration-react@1.2.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + ## 1.14.1-next.3 ### Patch Changes diff --git a/plugins/catalog-react/package.json b/plugins/catalog-react/package.json index 4afc5e579e..243ffa483b 100644 --- a/plugins/catalog-react/package.json +++ b/plugins/catalog-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-react", - "version": "1.14.1-next.3", + "version": "1.14.3-next.2", "description": "A frontend library that helps other Backstage plugins interact with the catalog", "backstage": { "role": "web-library", diff --git a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx index ee51020cbb..793d4741ad 100644 --- a/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx +++ b/plugins/catalog-react/src/components/CatalogFilterLayout/CatalogFilterLayout.tsx @@ -34,8 +34,10 @@ export const Filters = (props: { drawerAnchor?: 'left' | 'right' | 'top' | 'bottom'; }; }) => { - const isScreenSmallerThanBreakpoint = useMediaQuery((theme: Theme) => - theme.breakpoints.down(props.options?.drawerBreakpoint ?? 'md'), + const isScreenSmallerThanBreakpoint = useMediaQuery( + (theme: Theme) => + theme.breakpoints.down(props.options?.drawerBreakpoint ?? 'md'), + { noSsr: true }, ); const theme = useTheme(); const [filterDrawerOpen, setFilterDrawerOpen] = useState(false); diff --git a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx index eba4cc3a7a..fd88a7a31e 100644 --- a/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx +++ b/plugins/catalog-react/src/components/EntityAutocompletePicker/EntityAutocompletePicker.tsx @@ -31,7 +31,7 @@ import { useEntityList, } from '../../hooks/useEntityListProvider'; import { EntityFilter } from '../../types'; -import { reduceBackendCatalogFilters } from '../../utils'; +import { reduceBackendCatalogFilters } from '../../utils/filters'; /** @public */ export type AllowedEntityFilters = { diff --git a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx index 4eb0f53aa1..2b9f3307ef 100644 --- a/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx +++ b/plugins/catalog-react/src/components/EntityDisplayName/EntityDisplayName.tsx @@ -79,7 +79,6 @@ export const EntityDisplayName = ( // The innermost "body" content let content = <>{primaryTitle}; - // Optionally an icon, and wrapper around them both content = ( diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx index 9d9c25a233..7591d4c3ae 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.test.tsx @@ -402,17 +402,16 @@ describe('', () => { fireEvent.click(screen.getByTestId('owner-picker-expand')); + // // some-owner, some-owner-2, another-owner, another-owner-2 await waitFor(() => - expect(screen.getByText('Another Owner')).toBeInTheDocument(), + expect(screen.getByText('some-owner')).toBeInTheDocument(), ); - [ - 'some-owner', - 'Some Owner 2', - 'Another Owner in Another Namespace', - ].forEach(owner => { - expect(screen.getByText(owner)).toBeInTheDocument(); - }); + ['some-owner-2', 'another-owner', 'test-namespace/another-owner-2'].forEach( + owner => { + expect(screen.getByText(owner)).toBeInTheDocument(); + }, + ); expect(mockCatalogApi.getEntityFacets).toHaveBeenCalledTimes(1); @@ -423,9 +422,9 @@ describe('', () => { ); [ - 'some-owner-batch-2', - 'Some Owner Batch 2', - 'Another Owner in Another Namespace Batch 2', + 'some-owner-2-batch-2', + 'another-owner-batch-2', + 'test-namespace/another-owner-2-batch-2', ].forEach(owner => { expect(screen.getByText(owner)).toBeInTheDocument(); }); @@ -465,10 +464,8 @@ describe('', () => { , ); - expect(mockCatalogApi.getEntitiesByRefs).toHaveBeenCalledWith({ - entityRefs: [...ownerEntitiesBatch1, ...ownerEntitiesBatch2].map(entity => - stringifyEntityRef(entity), - ), + expect(mockCatalogApi.getEntityFacets).toHaveBeenCalledWith({ + facets: ['relations.ownedBy'], }); expect(updateFilters).toHaveBeenLastCalledWith({ owners: undefined, diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx index 57bf124bf6..ecbdae1d63 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/EntityOwnerPicker.tsx @@ -42,6 +42,7 @@ import { withStyles } from '@material-ui/core/styles'; import { useEntityPresentation } from '../../apis'; import { catalogReactTranslationRef } from '../../translation'; import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { PopperProps } from '@material-ui/core/Popper'; /** @public */ export type CatalogReactEntityOwnerPickerClassKey = 'input'; @@ -188,9 +189,7 @@ export const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => { {t('entityOwnerPicker.title')} ( -
{popperProps.children as ReactNode}
- )} + PopperComponent={Popper} multiple disableCloseOnSelect loading={loading} @@ -264,3 +263,7 @@ export const EntityOwnerPicker = (props?: EntityOwnerPickerProps) => {
); }; + +function Popper({ children }: PopperProps) { + return
{children as ReactNode}
; +} diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts index a3901825b3..a714b31327 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.test.ts @@ -17,7 +17,6 @@ import { renderHook, waitFor } from '@testing-library/react'; import { useFacetsEntities } from './useFacetsEntities'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; -import { Entity, parseEntityRef } from '@backstage/catalog-model'; const mockCatalogApi = catalogApiMock.mock(); @@ -37,25 +36,6 @@ describe('useFacetsEntities', () => { }, }); - const entitiesFromEntityRefs = ( - entityRefs: string[], - enrichedEntities: { [key: string]: Entity } = {}, - ) => ({ - items: entityRefs.map(ref => { - const compoundRef = parseEntityRef(ref); - return ( - enrichedEntities[ref] || { - apiVersion: 'backstage.io/v1beta1', - kind: compoundRef.kind, - metadata: { - name: compoundRef.name, - namespace: compoundRef.namespace, - }, - } - ); - }), - }); - it(`should return empty items when facets are loading`, () => { mockCatalogApi.getEntityFacets.mockReturnValue(new Promise(() => {})); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -82,9 +62,6 @@ describe('useFacetsEntities', () => { mockCatalogApi.getEntityFacets.mockResolvedValue( facetsFromEntityRefs(entityRefs), ); - mockCatalogApi.getEntitiesByRefs.mockResolvedValue( - entitiesFromEntityRefs(entityRefs), - ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -110,48 +87,20 @@ describe('useFacetsEntities', () => { }); }); - it(`should return the owners sorted by namespace, (displayName or title or name) and kind`, async () => { + it(`should return the owners sorted by kind, namespace and name`, async () => { const entityRefs = [ 'group:namespace/team-b', - 'component:default/c', + 'user:default/c', 'group:default/a', - 'component:default/a', - 'component:default/b', + 'user:default/a', + 'user:default/b', 'group:default/d', 'group:default/e', ]; - const enrichedEntities: { [key: string]: Entity } = { - 'group:default/a': { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'a', namespace: 'default', title: 'My title A' }, - }, - 'component:default/a': { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'a', namespace: 'default', title: 'My title B' }, - }, - 'group:default/d': { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'd', namespace: 'default' }, - spec: { profile: { displayName: 'My display name D' } }, - }, - 'group:default/e': { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'e', namespace: 'default' }, - spec: { profile: { displayName: 'My display name E' } }, - }, - }; - mockCatalogApi.getEntityFacets.mockResolvedValue( facetsFromEntityRefs(entityRefs), ); - mockCatalogApi.getEntitiesByRefs.mockResolvedValue( - entitiesFromEntityRefs(entityRefs, enrichedEntities), - ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -162,49 +111,48 @@ describe('useFacetsEntities', () => { items: [ { apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'b', namespace: 'default' }, - }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'c', namespace: 'default' }, + kind: 'group', + metadata: { name: 'a', namespace: 'default' }, }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', metadata: { name: 'd', namespace: 'default' }, - spec: { profile: { displayName: 'My display name D' } }, }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', metadata: { name: 'e', namespace: 'default' }, - spec: { profile: { displayName: 'My display name E' } }, - }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { - name: 'a', - namespace: 'default', - title: 'My title A', - }, - }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { - name: 'a', - namespace: 'default', - title: 'My title B', - }, }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', metadata: { name: 'team-b', namespace: 'namespace' }, }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { + name: 'a', + namespace: 'default', + }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { + name: 'b', + namespace: 'default', + }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { + name: 'c', + namespace: 'default', + }, + }, ], }, loading: false, @@ -215,18 +163,15 @@ describe('useFacetsEntities', () => { it(`should paginate the data accordingly`, async () => { const entityRefs = [ 'group:namespace/team-b', - 'component:default/c', + 'user:default/c', 'group:default/a', - 'component:default/a', - 'component:default/b', + 'user:default/a', + 'user:default/b', ]; mockCatalogApi.getEntityFacets.mockResolvedValue( facetsFromEntityRefs(entityRefs), ); - mockCatalogApi.getEntitiesByRefs.mockResolvedValue( - entitiesFromEntityRefs(entityRefs), - ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); @@ -237,13 +182,13 @@ describe('useFacetsEntities', () => { items: [ { apiVersion: 'backstage.io/v1beta1', - kind: 'component', + kind: 'group', metadata: { name: 'a', namespace: 'default' }, }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', - metadata: { name: 'a', namespace: 'default' }, + metadata: { name: 'team-b', namespace: 'namespace' }, }, ], cursor: 'eyJ0ZXh0IjoiIiwic3RhcnQiOjJ9', @@ -257,11 +202,6 @@ describe('useFacetsEntities', () => { expect(result.current[0]).toEqual({ value: { items: [ - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'a', namespace: 'default' }, - }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', @@ -269,13 +209,18 @@ describe('useFacetsEntities', () => { }, { apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'b', namespace: 'default' }, + kind: 'group', + metadata: { name: 'team-b', namespace: 'namespace' }, }, { apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'c', namespace: 'default' }, + kind: 'user', + metadata: { name: 'a', namespace: 'default' }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { name: 'b', namespace: 'default' }, }, ], cursor: 'eyJ0ZXh0IjoiIiwic3RhcnQiOjR9', @@ -289,31 +234,31 @@ describe('useFacetsEntities', () => { expect(result.current[0]).toEqual({ value: { items: [ - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'a', namespace: 'default' }, - }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', metadata: { name: 'a', namespace: 'default' }, }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'b', namespace: 'default' }, - }, - { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'c', namespace: 'default' }, - }, { apiVersion: 'backstage.io/v1beta1', kind: 'group', metadata: { name: 'team-b', namespace: 'namespace' }, }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { name: 'a', namespace: 'default' }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { name: 'b', namespace: 'default' }, + }, + { + apiVersion: 'backstage.io/v1beta1', + kind: 'user', + metadata: { name: 'c', namespace: 'default' }, + }, ], }, loading: false, @@ -337,34 +282,15 @@ describe('useFacetsEntities', () => { mockCatalogApi.getEntityFacets.mockResolvedValue( facetsFromEntityRefs(entityRefs), ); - const enrichedEntities: { [key: string]: Entity } = { - 'group:default/go': { - apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'go', namespace: 'default', title: 'Hidden Spider' }, - }, - 'component:default/lemon': { - apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'lemon', namespace: 'default' }, - spec: { - profile: { displayName: 'Lemon Spider' }, - }, - }, - }; - mockCatalogApi.getEntitiesByRefs.mockResolvedValue( - entitiesFromEntityRefs(entityRefs, enrichedEntities), - ); const { result } = renderHook(() => useFacetsEntities({ enabled: true })); result.current[1]({ text: 'der ' }); + await waitFor(() => { expect(result.current[0]).toEqual({ value: { items: [ - enrichedEntities['group:default/go'], - enrichedEntities['component:default/lemon'], { apiVersion: 'backstage.io/v1beta1', kind: 'component', @@ -372,13 +298,13 @@ describe('useFacetsEntities', () => { }, { apiVersion: 'backstage.io/v1beta1', - kind: 'group', - metadata: { name: 'spiderman', namespace: 'namespace' }, + kind: 'component', + metadata: { name: 'a-component', namespace: 'spiders' }, }, { apiVersion: 'backstage.io/v1beta1', - kind: 'component', - metadata: { name: 'a-component', namespace: 'spiders' }, + kind: 'group', + metadata: { name: 'spiderman', namespace: 'namespace' }, }, { apiVersion: 'backstage.io/v1beta1', diff --git a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts index f43bba97c7..a1d7693c1d 100644 --- a/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts +++ b/plugins/catalog-react/src/components/EntityOwnerPicker/useFacetsEntities.ts @@ -17,8 +17,7 @@ import { useApi } from '@backstage/core-plugin-api'; import useAsyncFn from 'react-use/esm/useAsyncFn'; import { catalogApiRef } from '../../api'; import { useState } from 'react'; -import { Entity } from '@backstage/catalog-model'; -import get from 'lodash/get'; +import { Entity, parseEntityRef } from '@backstage/catalog-model'; type FacetsCursor = { start: number; @@ -34,15 +33,13 @@ type FacetsInitialRequest = { text: string; }; -const maybeString = (value: unknown): string | undefined => - typeof value === 'string' ? value : undefined; - /** * This hook asynchronously loads the entity owners using the facets endpoint. * EntityOwnerPicker uses this hook when mode="owners-only" is passed as prop. * All the owners are kept internally in memory and rendered in batches once requested * by the frontend. The values returned by this hook are compatible with `useQueryEntities` * hook, which is also used by EntityOwnerPicker. + * In this mode, the EntityOwnerPicker won't show detailed information of the owners. */ export function useFacetsEntities({ enabled }: { enabled: boolean }) { const catalogApi = useApi(catalogApiRef); @@ -52,37 +49,30 @@ export function useFacetsEntities({ enabled }: { enabled: boolean }) { return []; } const facet = 'relations.ownedBy'; - const facetsResponse = await catalogApi.getEntityFacets({ - facets: [facet], - }); - const entityRefs = facetsResponse.facets[facet]?.map(e => e.value) ?? []; return catalogApi - .getEntitiesByRefs({ entityRefs }) - .then(resp => - resp.items - .filter(entity => entity !== undefined) - .map(entity => entity as Entity) + .getEntityFacets({ facets: [facet] }) + .then(response => + response.facets[facet] + .map(e => e.value) + .map(ref => { + const { kind, name, namespace } = parseEntityRef(ref); + return { + apiVersion: 'backstage.io/v1beta1', + kind, + metadata: { name, namespace }, + }; + }) .sort( (a, b) => - (a.metadata.namespace || '').localeCompare( - b.metadata.namespace || '', + a.kind.localeCompare(b.kind, 'en-US') || + a.metadata.namespace.localeCompare( + b.metadata.namespace, 'en-US', ) || - ( - maybeString(get(a, 'spec.profile.displayName')) || - a.metadata.title || - a.metadata.name - ).localeCompare( - maybeString(get(b, 'spec.profile.displayName')) || - b.metadata.title || - b.metadata.name, - 'en-US', - ) || - a.kind.localeCompare(b.kind, 'en-US'), + a.metadata.name.localeCompare(b.metadata.name, 'en-US'), ), ) - .then(entities => entities) .catch(() => []); }); @@ -161,10 +151,6 @@ function filterEntity(text: string, entity: Entity) { return ( entity.kind.includes(normalizedText) || entity.metadata.namespace?.includes(normalizedText) || - entity.metadata.name.includes(normalizedText) || - entity.metadata.title?.includes(normalizedText) || - (get(entity, 'spec.profile.displayName') as unknown as string)?.includes( - normalizedText, - ) + entity.metadata.name.includes(normalizedText) ); } diff --git a/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.ts b/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.ts index cecd0e4db7..fa564382d8 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.ts +++ b/plugins/catalog-react/src/components/UserListPicker/useAllEntitiesCount.ts @@ -20,7 +20,7 @@ import { useMemo, useRef } from 'react'; import useAsync from 'react-use/esm/useAsync'; import { catalogApiRef } from '../../api'; import { useEntityList } from '../../hooks'; -import { reduceCatalogFilters } from '../../utils'; +import { reduceCatalogFilters } from '../../utils/filters'; export function useAllEntitiesCount() { const catalogApi = useApi(catalogApiRef); diff --git a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts index 10481e80a8..dbdc040165 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts +++ b/plugins/catalog-react/src/components/UserListPicker/useOwnedEntitiesCount.ts @@ -21,7 +21,7 @@ import useAsync from 'react-use/esm/useAsync'; import { catalogApiRef } from '../../api'; import { EntityOwnerFilter, EntityUserFilter } from '../../filters'; import { useEntityList } from '../../hooks'; -import { CatalogFilters, reduceCatalogFilters } from '../../utils'; +import { CatalogFilters, reduceCatalogFilters } from '../../utils/filters'; import useAsyncFn from 'react-use/esm/useAsyncFn'; import useDeepCompareEffect from 'react-use/esm/useDeepCompareEffect'; diff --git a/plugins/catalog-react/src/components/UserListPicker/useStarredEntitiesCount.ts b/plugins/catalog-react/src/components/UserListPicker/useStarredEntitiesCount.ts index 082c683642..70dde024f8 100644 --- a/plugins/catalog-react/src/components/UserListPicker/useStarredEntitiesCount.ts +++ b/plugins/catalog-react/src/components/UserListPicker/useStarredEntitiesCount.ts @@ -23,7 +23,7 @@ import useAsync from 'react-use/esm/useAsync'; import { catalogApiRef } from '../../api'; import { EntityUserFilter } from '../../filters'; import { useEntityList, useStarredEntities } from '../../hooks'; -import { reduceCatalogFilters } from '../../utils'; +import { reduceCatalogFilters } from '../../utils/filters'; export function useStarredEntitiesCount() { const catalogApi = useApi(catalogApiRef); diff --git a/plugins/catalog-react/src/filters.test.ts b/plugins/catalog-react/src/filters.test.ts index 8ddac7e53b..12ebc4ba04 100644 --- a/plugins/catalog-react/src/filters.test.ts +++ b/plugins/catalog-react/src/filters.test.ts @@ -72,6 +72,33 @@ const templates: TemplateEntityV1beta3[] = [ }, ]; +const users: Entity[] = [ + { + apiVersion: '1', + kind: 'User', + metadata: { + name: 'jd1234', + }, + spec: { + profile: { + displayName: 'DOE, JOHN', + }, + }, + }, + { + apiVersion: '1', + kind: 'User', + metadata: { + name: 'fb3456', + }, + spec: { + profile: { + displayName: 'BAR, FOO', + }, + }, + }, +]; + describe('EntityTextFilter', () => { it('should search name', () => { const filter = new EntityTextFilter('app'); @@ -96,6 +123,12 @@ describe('EntityTextFilter', () => { expect(filter.filterEntity(entities[0])).toBeFalsy(); expect(filter.filterEntity(entities[1])).toBeTruthy(); }); + + it('should search display name', () => { + const filter = new EntityTextFilter('doe'); + expect(filter.filterEntity(users[0])).toBeTruthy(); + expect(filter.filterEntity(users[1])).toBeFalsy(); + }); }); describe('EntityOrphanFilter', () => { diff --git a/plugins/catalog-react/src/filters.ts b/plugins/catalog-react/src/filters.ts index 08be27a561..c033298983 100644 --- a/plugins/catalog-react/src/filters.ts +++ b/plugins/catalog-react/src/filters.ts @@ -22,7 +22,7 @@ import { } from '@backstage/catalog-model'; import { AlphaEntity } from '@backstage/catalog-model/alpha'; import { EntityFilter, UserListFilterKind } from './types'; -import { getEntityRelations } from './utils'; +import { getEntityRelations } from './utils/getEntityRelations'; /** * Filter entities based on Kind. @@ -94,6 +94,7 @@ export class EntityTextFilter implements EntityFilter { const partialMatch = this.toUpperArray([ entity.metadata.name, entity.metadata.title, + (entity.spec?.profile as { displayName?: string })?.displayName, ]); for (const word of words) { diff --git a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx index 274ec52a18..b96357eb62 100644 --- a/plugins/catalog-react/src/hooks/useEntityListProvider.tsx +++ b/plugins/catalog-react/src/hooks/useEntityListProvider.tsx @@ -48,7 +48,7 @@ import { reduceBackendCatalogFilters, reduceCatalogFilters, reduceEntityFilters, -} from '../utils'; +} from '../utils/filters'; import { useApi } from '@backstage/core-plugin-api'; import { QueryEntitiesResponse } from '@backstage/catalog-client'; diff --git a/plugins/catalog-react/src/utils/index.ts b/plugins/catalog-react/src/utils/index.ts index 5afc32af63..5b2159ae2f 100644 --- a/plugins/catalog-react/src/utils/index.ts +++ b/plugins/catalog-react/src/utils/index.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export * from './filters'; + export { getEntityRelations } from './getEntityRelations'; export { getEntitySourceLocation } from './getEntitySourceLocation'; export type { EntitySourceLocation } from './getEntitySourceLocation'; diff --git a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md index 6e254a9591..027c99666b 100644 --- a/plugins/catalog-unprocessed-entities-common/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @backstage/plugin-catalog-unprocessed-entities-common +## 0.0.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.0.5 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 + ## 0.0.4 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities-common/package.json b/plugins/catalog-unprocessed-entities-common/package.json index 75a76166bd..4be731fc7d 100644 --- a/plugins/catalog-unprocessed-entities-common/package.json +++ b/plugins/catalog-unprocessed-entities-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog-unprocessed-entities-common", - "version": "0.0.4", + "version": "0.0.6-next.0", "description": "Common functionalities for the catalog-unprocessed-entities plugin", "backstage": { "role": "common-library", diff --git a/plugins/catalog-unprocessed-entities/CHANGELOG.md b/plugins/catalog-unprocessed-entities/CHANGELOG.md index 0bee10ff74..f06c156ebd 100644 --- a/plugins/catalog-unprocessed-entities/CHANGELOG.md +++ b/plugins/catalog-unprocessed-entities/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-catalog-unprocessed-entities +## 0.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## 0.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## 0.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + +## 0.2.10 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + ## 0.2.10-next.2 ### Patch Changes diff --git a/plugins/catalog-unprocessed-entities/package.json b/plugins/catalog-unprocessed-entities/package.json index 7fa8da42b8..e83b13e26f 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.10-next.2", + "version": "0.2.12-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "catalog-unprocessed-entities", diff --git a/plugins/catalog/CHANGELOG.md b/plugins/catalog/CHANGELOG.md index ceddf8daa0..4df5aa6fd7 100644 --- a/plugins/catalog/CHANGELOG.md +++ b/plugins/catalog/CHANGELOG.md @@ -1,5 +1,103 @@ # @backstage/plugin-catalog +## 1.26.0-next.2 + +### Minor Changes + +- 25beb82: Adds an optional columns attribute to HasSubdomainsCardProps and changes its default columns +- 39f1abc: Consistent title behaviour across CatalogTable, CursorPaginatedCatalogTable, and OffsetPaginatedCatalogTable. + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + +## 1.25.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + +## 1.25.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + +## 1.25.0 + +### Minor Changes + +- 50df3c8: - Updated EntityLayout component to implement breadcrumb navigation based on the entity relations. + + - Added parentEntityRelations prop to EntityLayoutProps to specify relation types for parent entities. + +- 79e9631: Allow `OffsetPaginatedCatalogTable` to configure Table options and `CursorPaginatedCatalogTable` to configure `paginationPosition`. + +### Patch Changes + +- 2a67594: Fixed an issue causing the `CatalogIndexPage` to not properly filter results when using offset pagination. +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + ## 1.25.0-next.3 ### Minor Changes diff --git a/plugins/catalog/package.json b/plugins/catalog/package.json index 2999350ab1..4e030cb90b 100644 --- a/plugins/catalog/package.json +++ b/plugins/catalog/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-catalog", - "version": "1.25.0-next.3", + "version": "1.26.0-next.2", "description": "The Backstage plugin for browsing the Backstage catalog", "backstage": { "role": "frontend-plugin", diff --git a/plugins/catalog/report-alpha.api.md b/plugins/catalog/report-alpha.api.md index 1b1ce54d92..3a9f0c6c33 100644 --- a/plugins/catalog/report-alpha.api.md +++ b/plugins/catalog/report-alpha.api.md @@ -146,21 +146,6 @@ const _default: FrontendPlugin< unregisterRedirect: ExternalRouteRef; }, { - 'api:catalog': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'nav-item:catalog': ExtensionDefinition<{ kind: 'nav-item'; name: undefined; @@ -182,6 +167,21 @@ const _default: FrontendPlugin< routeRef: RouteRef; }; }>; + 'api:catalog': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; 'api:catalog/starred-entities': ExtensionDefinition<{ kind: 'api'; name: 'starred-entities'; diff --git a/plugins/catalog/report.api.md b/plugins/catalog/report.api.md index ffb46afc6e..3692a919b3 100644 --- a/plugins/catalog/report.api.md +++ b/plugins/catalog/report.api.md @@ -10,6 +10,7 @@ import { BackstagePlugin } from '@backstage/core-plugin-api'; import { CatalogApi } from '@backstage/plugin-catalog-react'; import { ComponentEntity } from '@backstage/catalog-model'; import { CompoundEntityRef } from '@backstage/catalog-model'; +import { DomainEntity } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; import { EntityListContextProps } from '@backstage/plugin-catalog-react'; import { EntityListPagination } from '@backstage/plugin-catalog-react'; @@ -64,6 +65,8 @@ export interface AboutFieldProps { // (undocumented) children?: React_2.ReactNode; // (undocumented) + className?: string; + // (undocumented) gridSizes?: Record; // (undocumented) label: string; @@ -154,7 +157,7 @@ export interface CatalogSearchResultListItemProps { result?: IndexableDocument; } -// @public (undocumented) +// @public export const CatalogTable: { (props: CatalogTableProps): React_2.JSX.Element; columns: Readonly<{ @@ -212,6 +215,7 @@ export interface CatalogTableProps { subtitle?: string; // (undocumented) tableOptions?: TableProps['options']; + title?: string; } // @public (undocumented) @@ -582,6 +586,8 @@ export interface HasSubcomponentsCardProps { // @public (undocumented) export interface HasSubdomainsCardProps { + // (undocumented) + columns?: TableColumn[]; // (undocumented) tableOptions?: TableOptions; // (undocumented) diff --git a/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts index f4b7771d04..5c06dc1ca2 100644 --- a/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts +++ b/plugins/catalog/src/apis/StarredEntitiesApi/DefaultStarredEntitiesApi.ts @@ -69,7 +69,7 @@ export class DefaultStarredEntitiesApi implements StarredEntitiesApi { >(); private readonly observable = new ObservableImpl>(subscriber => { - // forward the the latest value + // forward the latest value subscriber.next(new Set(this.starredEntities)); this.subscribers.add(subscriber); diff --git a/plugins/catalog/src/components/AboutCard/AboutContent.tsx b/plugins/catalog/src/components/AboutCard/AboutContent.tsx index f6d2d80264..07547c8949 100644 --- a/plugins/catalog/src/components/AboutCard/AboutContent.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutContent.tsx @@ -132,6 +132,7 @@ export function AboutContent(props: AboutContentProps) { {ownedByRelations.length > 0 && ( diff --git a/plugins/catalog/src/components/AboutCard/AboutField.tsx b/plugins/catalog/src/components/AboutCard/AboutField.tsx index 7587867af0..15e02307f0 100644 --- a/plugins/catalog/src/components/AboutCard/AboutField.tsx +++ b/plugins/catalog/src/components/AboutCard/AboutField.tsx @@ -48,11 +48,12 @@ export interface AboutFieldProps { value?: string; gridSizes?: Record; children?: React.ReactNode; + className?: string; } /** @public */ export function AboutField(props: AboutFieldProps) { - const { label, value, gridSizes, children } = props; + const { label, value, gridSizes, children, className } = props; const classes = useStyles(); const childElements = useElementFilter(children, c => c.getElements()); @@ -67,7 +68,7 @@ export function AboutField(props: AboutFieldProps) { ); return ( - + {label} diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx index 5b7f28e26a..13ee7593b9 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.test.tsx @@ -84,6 +84,19 @@ describe('CatalogTable component', () => { ).resolves.toBeInTheDocument(); }); + it('should a custom title and subtitle when passed in', async () => { + await renderInTestApp( + + + + + , + ); + + expect(screen.queryByText('My Title')).toBeInTheDocument(); + expect(screen.queryByText('My Subtitle')).toBeInTheDocument(); + }); + it('should display entity names when loading has finished and no error occurred', async () => { await renderInTestApp( diff --git a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx index 2d5e78a0d6..944e795709 100644 --- a/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CatalogTable.tsx @@ -49,6 +49,7 @@ import { defaultCatalogTableColumnsFunc } from './defaultCatalogTableColumnsFunc import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { catalogTranslationRef } from '../../alpha/translation'; import { FavoriteToggleIcon } from '@backstage/core-components'; +import { CatalogTableToolbar } from './CatalogTableToolbar'; /** * Props for {@link CatalogTable}. @@ -60,6 +61,11 @@ export interface CatalogTableProps { actions?: TableProps['actions']; tableOptions?: TableProps['options']; emptyContent?: ReactNode; + /** + * A static title to use for the table. If not provided, a title will be + * generated based on the current Kind and Type filters and total number of items. + */ + title?: string; subtitle?: string; } @@ -73,7 +79,16 @@ const refCompare = (a: Entity, b: Entity) => { return toRef(a).localeCompare(toRef(b)); }; -/** @public */ +/** + * CatalogTable is a wrapper around the Table component that is pre-configured + * to display catalog entities. + * + * @remarks + * + * See {@link https://backstage.io/docs/features/software-catalog/catalog-customization} + * + * @public + */ export const CatalogTable = (props: CatalogTableProps) => { const { columns = defaultCatalogTableColumnsFunc, @@ -173,14 +188,11 @@ export const CatalogTable = (props: CatalogTableProps) => { const currentCount = typeof totalItems === 'number' ? `(${totalItems})` : ''; // TODO(timbonicus): remove the title from the CatalogTable once using EntitySearchBar const titlePreamble = capitalize(filters.user?.value ?? 'all'); - const title = [ - titlePreamble, - currentType, - pluralize(currentKind), - currentCount, - ] - .filter(s => s) - .join(' '); + const title = + props.title || + [titlePreamble, currentType, pluralize(currentKind), currentCount] + .filter(s => s) + .join(' '); const actions = props.actions || defaultActions; const options = { @@ -235,6 +247,9 @@ export const CatalogTable = (props: CatalogTableProps) => { pageSizeOptions: [20, 50, 100], ...options, }} + components={{ + Toolbar: CatalogTableToolbar, + }} title={title} data={rows} actions={actions} diff --git a/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.test.tsx index adc69794ae..b0deec9679 100644 --- a/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.test.tsx @@ -63,6 +63,22 @@ describe('CursorPaginatedCatalogTable', () => { ); }; + it('should display the title and subtitle when passed in', async () => { + await renderInTestApp( + wrapInContext( + , + ), + ); + + expect(screen.queryByText('My Title')).toBeInTheDocument(); + expect(screen.queryByText('My Subtitle')).toBeInTheDocument(); + }); + it('should display all the items', async () => { await renderInTestApp( wrapInContext( diff --git a/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.tsx index 7198f8a60c..843d5be2c8 100644 --- a/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/CursorPaginatedCatalogTable.tsx @@ -30,12 +30,10 @@ type PaginatedCatalogTableProps = { */ export function CursorPaginatedCatalogTable(props: PaginatedCatalogTableProps) { - const { columns, data, next, prev, title, isLoading, options, ...restProps } = - props; + const { columns, data, next, prev, options, ...restProps } = props; return ( ); diff --git a/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.test.tsx b/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.test.tsx index aad9b7cb3d..e2e73c5af8 100644 --- a/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.test.tsx +++ b/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.test.tsx @@ -62,6 +62,28 @@ describe('OffsetPaginatedCatalogTable', () => { ); }; + it('should display the title and subtitle when passed in', async () => { + await renderInTestApp( + wrapInContext( + , + { + setOffset: jest.fn(), + limit: Number.MAX_SAFE_INTEGER, + offset: 0, + totalItems: data.length, + }, + ), + ); + + expect(screen.queryByText('My Title')).toBeInTheDocument(); + expect(screen.queryByText('My Subtitle')).toBeInTheDocument(); + }); + it('should display all the items', async () => { await renderInTestApp( wrapInContext( diff --git a/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.tsx b/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.tsx index 7febfc2d32..7ebf791046 100644 --- a/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.tsx +++ b/plugins/catalog/src/components/CatalogTable/OffsetPaginatedCatalogTable.tsx @@ -27,7 +27,7 @@ import { CatalogTableToolbar } from './CatalogTableToolbar'; export function OffsetPaginatedCatalogTable( props: TableProps, ) { - const { columns, data, isLoading, options } = props; + const { columns, data, options, ...restProps } = props; const { setLimit, setOffset, limit, totalItems, offset } = useEntityList(); const [page, setPage] = React.useState( @@ -65,7 +65,7 @@ export function OffsetPaginatedCatalogTable( }} totalCount={totalItems} localization={{ pagination: { labelDisplayedRows: '' } }} - isLoading={isLoading} + {...restProps} /> ); } diff --git a/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx index 71705ea90f..b52f5eacf7 100644 --- a/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx +++ b/plugins/catalog/src/components/HasSubdomainsCard/HasSubdomainsCard.tsx @@ -14,12 +14,17 @@ * limitations under the License. */ -import { RELATION_HAS_PART } from '@backstage/catalog-model'; -import { InfoCardVariants, TableOptions } from '@backstage/core-components'; +import { DomainEntity, RELATION_HAS_PART } from '@backstage/catalog-model'; +import { + InfoCardVariants, + TableColumn, + TableOptions, +} from '@backstage/core-components'; import React from 'react'; import { - asComponentEntities, - componentEntityColumns, + asDomainEntities, + domainEntityColumns, + domainEntityHelpLink, RelatedEntitiesCard, } from '../RelatedEntitiesCard'; import { catalogTranslationRef } from '../../alpha/translation'; @@ -29,6 +34,7 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; export interface HasSubdomainsCardProps { variant?: InfoCardVariants; tableOptions?: TableOptions; + columns?: TableColumn[]; title?: string; } @@ -36,8 +42,9 @@ export function HasSubdomainsCard(props: HasSubdomainsCardProps) { const { t } = useTranslationRef(catalogTranslationRef); const { variant = 'gridItem', - tableOptions = {}, title = t('hasSubdomainsCard.title'), + columns = domainEntityColumns, + tableOptions = {}, } = props; return ( ); diff --git a/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx b/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx index 5b57cbd80e..40481614e2 100644 --- a/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx +++ b/plugins/catalog/src/components/RelatedEntitiesCard/RelatedEntitiesCard.tsx @@ -33,10 +33,13 @@ import { } from '@backstage/core-components'; import { asComponentEntities, + asDomainEntities, asResourceEntities, asSystemEntities, componentEntityColumns, componentEntityHelpLink, + domainEntityColumns, + domainEntityHelpLink, resourceEntityColumns, resourceEntityHelpLink, systemEntityColumns, @@ -137,3 +140,6 @@ RelatedEntitiesCard.asResourceEntities = asResourceEntities; RelatedEntitiesCard.systemEntityColumns = systemEntityColumns; RelatedEntitiesCard.systemEntityHelpLink = systemEntityHelpLink; RelatedEntitiesCard.asSystemEntities = asSystemEntities; +RelatedEntitiesCard.domainEntityColums = domainEntityColumns; +RelatedEntitiesCard.domainEntityHelpLink = domainEntityHelpLink; +RelatedEntitiesCard.asDomainEntities = asDomainEntities; diff --git a/plugins/catalog/src/components/RelatedEntitiesCard/presets.ts b/plugins/catalog/src/components/RelatedEntitiesCard/presets.ts index 8e3040ccf9..68930c578b 100644 --- a/plugins/catalog/src/components/RelatedEntitiesCard/presets.ts +++ b/plugins/catalog/src/components/RelatedEntitiesCard/presets.ts @@ -15,6 +15,7 @@ */ import { ComponentEntity, + DomainEntity, Entity, ResourceEntity, SystemEntity, @@ -55,3 +56,13 @@ export const systemEntityHelpLink: string = 'https://backstage.io/docs/features/software-catalog/descriptor-format#kind-system'; export const asSystemEntities = (entities: Entity[]): SystemEntity[] => entities as SystemEntity[]; + +export const domainEntityColumns: TableColumn[] = [ + EntityTable.columns.createEntityRefColumn({ defaultKind: 'domain' }), + EntityTable.columns.createOwnerColumn(), + EntityTable.columns.createMetadataDescriptionColumn(), +]; +export const domainEntityHelpLink: string = + 'https://backstage.io/docs/features/software-catalog/descriptor-format#kind-domain'; +export const asDomainEntities = (entities: Entity[]): DomainEntity[] => + entities as DomainEntity[]; diff --git a/plugins/config-schema/CHANGELOG.md b/plugins/config-schema/CHANGELOG.md index 0dda126c1a..b4393708db 100644 --- a/plugins/config-schema/CHANGELOG.md +++ b/plugins/config-schema/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-config-schema +## 0.1.63-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + +## 0.1.63-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.1.63-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.1.61 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + ## 0.1.61-next.2 ### Patch Changes diff --git a/plugins/config-schema/package.json b/plugins/config-schema/package.json index cf248a2311..d48ca8dbc3 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.61-next.2", + "version": "0.1.63-next.2", "description": "A Backstage plugin that lets you browse the configuration schema of your app", "backstage": { "role": "frontend-plugin", diff --git a/plugins/config-schema/src/components/SchemaView/ArrayView.tsx b/plugins/config-schema/src/components/SchemaView/ArrayView.tsx deleted file mode 100644 index abe2cfc327..0000000000 --- a/plugins/config-schema/src/components/SchemaView/ArrayView.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2021 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 Box from '@material-ui/core/Box'; -import Typography from '@material-ui/core/Typography'; -import { Schema } from 'jsonschema'; -import React from 'react'; -import { ChildView } from './ChildView'; -import { MetadataView } from './MetadataView'; -import { SchemaViewProps } from './types'; - -export function ArrayView({ path, depth, schema }: SchemaViewProps) { - const itemDepth = depth + 1; - const itemPath = path ? `${path}[]` : '[]'; - const itemSchema = schema.items; - - return ( - <> - - {schema.description && ( - - {schema.description} - - )} - - - Items - - {schema.additionalItems && schema.additionalItems !== true && ( - <> - Additional Items - - - )} - - ); -} diff --git a/plugins/config-schema/src/components/SchemaView/ChildView.tsx b/plugins/config-schema/src/components/SchemaView/ChildView.tsx deleted file mode 100644 index b39e445688..0000000000 --- a/plugins/config-schema/src/components/SchemaView/ChildView.tsx +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2021 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 { JsonValue } from '@backstage/types'; -import Box from '@material-ui/core/Box'; -import Chip from '@material-ui/core/Chip'; -import Divider from '@material-ui/core/Divider'; -import Typography from '@material-ui/core/Typography'; -import { makeStyles } from '@material-ui/core/styles'; -import { Schema } from 'jsonschema'; -import React, { useEffect, useRef } from 'react'; -import { useScrollTargets } from '../ScrollTargetsContext/ScrollTargetsContext'; -import { SchemaView } from './SchemaView'; - -export interface MetadataViewRowProps { - label: string; - text?: string; - data?: JsonValue; -} - -function titleVariant(depth: number) { - if (depth <= 1) { - return 'h2'; - } else if (depth === 2) { - return 'h3'; - } else if (depth === 3) { - return 'h4'; - } else if (depth === 4) { - return 'h5'; - } - return 'h6'; -} - -const useChildViewStyles = makeStyles(theme => ({ - title: { - marginBottom: 0, - }, - chip: { - marginLeft: theme.spacing(1), - marginRight: 0, - marginBottom: 0, - }, -})); - -export function ChildView({ - path, - depth, - schema, - required, - lastChild, -}: { - path: string; - depth: number; - schema?: Schema; - required?: boolean; - lastChild?: boolean; -}) { - const classes = useChildViewStyles(); - const titleRef = useRef(null); - const scroll = useScrollTargets(); - - useEffect(() => { - return scroll?.setScrollListener(path, () => { - titleRef.current?.scrollIntoView({ behavior: 'smooth' }); - }); - }, [scroll, path]); - - const chips = new Array(); - const chipProps = { size: 'small' as const, classes: { root: classes.chip } }; - - if (required) { - chips.push( - , - ); - } - - const visibility = (schema as { visibility?: string })?.visibility; - if (visibility === 'frontend') { - chips.push( - , - ); - } else if (visibility === 'secret') { - chips.push( - , - ); - } - - return ( - - - - - - {path} - - {chips.length > 0 && } - {chips} - - {schema && ( - - )} - - - ); -} diff --git a/plugins/config-schema/src/components/SchemaView/MatchView.tsx b/plugins/config-schema/src/components/SchemaView/MatchView.tsx deleted file mode 100644 index ba97ff9db5..0000000000 --- a/plugins/config-schema/src/components/SchemaView/MatchView.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2021 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 Typography from '@material-ui/core/Typography'; -import { Schema } from 'jsonschema'; -import React from 'react'; -import { ChildView } from './ChildView'; - -export function MatchView({ - path, - depth, - schema, - label, -}: { - path: string; - depth: number; - schema: Schema[]; - label: string; -}) { - return ( - <> - {label} - {schema.map((optionSchema, index) => ( - - ))} - - ); -} diff --git a/plugins/config-schema/src/components/SchemaView/MetadataView.tsx b/plugins/config-schema/src/components/SchemaView/MetadataView.tsx deleted file mode 100644 index f3de041bed..0000000000 --- a/plugins/config-schema/src/components/SchemaView/MetadataView.tsx +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2021 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 { JsonValue } from '@backstage/types'; -import Paper from '@material-ui/core/Paper'; -import Table from '@material-ui/core/Table'; -import TableBody from '@material-ui/core/TableBody'; -import TableCell from '@material-ui/core/TableCell'; -import TableRow from '@material-ui/core/TableRow'; -import Typography from '@material-ui/core/Typography'; -import { Schema } from 'jsonschema'; -import React from 'react'; - -export interface MetadataViewRowProps { - label: string; - text?: string; - data?: JsonValue; -} - -export function MetadataViewRow({ label, text, data }: MetadataViewRowProps) { - if (text === undefined && data === undefined) { - return null; - } - return ( - - - - {label} - - - - - {data ? JSON.stringify(data) : text} - - - - ); -} - -export function MetadataView({ schema }: { schema: Schema }) { - return ( - -
- - - - {schema.additionalProperties === true && ( - - )} - {schema.additionalItems === true && ( - - )} - - - - - - - - - - - - - - - -
- - ); -} diff --git a/plugins/config-schema/src/components/SchemaView/ObjectView.tsx b/plugins/config-schema/src/components/SchemaView/ObjectView.tsx deleted file mode 100644 index c7cf000e10..0000000000 --- a/plugins/config-schema/src/components/SchemaView/ObjectView.tsx +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2021 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 Box from '@material-ui/core/Box'; -import Typography from '@material-ui/core/Typography'; -import React from 'react'; -import { ChildView } from './ChildView'; -import { MetadataView } from './MetadataView'; -import { SchemaViewProps } from './types'; - -function isRequired(name: string, required?: boolean | string[]) { - if (required === true) { - return true; - } - if (Array.isArray(required)) { - return required.includes(name); - } - return false; -} - -export function ObjectView({ path, depth, schema }: SchemaViewProps) { - const properties = Object.entries(schema.properties ?? {}); - const patternProperties = Object.entries(schema.patternProperties ?? {}); - - return ( - <> - {depth > 0 && ( - - {schema.description && ( - - {schema.description} - - )} - - - )} - {properties.length > 0 && ( - <> - {depth > 0 && Properties} - {properties.map(([name, propSchema], index) => ( - - ))} - - )} - {patternProperties.length > 0 && ( - <> - {depth > 0 && ( - Pattern Properties - )} - {patternProperties.map(([name, propSchema], index) => ( - ` : name} - depth={depth + 1} - schema={propSchema} - lastChild={index === patternProperties.length - 1} - required={isRequired(name, schema.required)} - /> - ))} - - )} - {schema.additionalProperties && schema.additionalProperties !== true && ( - <> - Additional Properties - - - )} - - ); -} diff --git a/plugins/config-schema/src/components/SchemaView/SchemaView.tsx b/plugins/config-schema/src/components/SchemaView/SchemaView.tsx index defb7fc353..d7a8db4f69 100644 --- a/plugins/config-schema/src/components/SchemaView/SchemaView.tsx +++ b/plugins/config-schema/src/components/SchemaView/SchemaView.tsx @@ -14,11 +14,20 @@ * limitations under the License. */ -import React from 'react'; -import { ArrayView } from './ArrayView'; -import { MatchView } from './MatchView'; -import { ObjectView } from './ObjectView'; -import { ScalarView } from './ScalarView'; +import { JsonValue } from '@backstage/types'; +import Box from '@material-ui/core/Box'; +import Chip from '@material-ui/core/Chip'; +import Divider from '@material-ui/core/Divider'; +import Paper from '@material-ui/core/Paper'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableRow from '@material-ui/core/TableRow'; +import Typography from '@material-ui/core/Typography'; +import { makeStyles } from '@material-ui/core/styles'; +import { Schema } from 'jsonschema'; +import React, { useEffect, useRef } from 'react'; +import { useScrollTargets } from '../ScrollTargetsContext/ScrollTargetsContext'; import { SchemaViewProps } from './types'; export function SchemaView(props: SchemaViewProps) { @@ -60,3 +69,337 @@ export function SchemaView(props: SchemaViewProps) { return ; } } + +function ArrayView({ path, depth, schema }: SchemaViewProps) { + const itemDepth = depth + 1; + const itemPath = path ? `${path}[]` : '[]'; + const itemSchema = schema.items; + + return ( + <> + + {schema.description && ( + + {schema.description} + + )} + + + Items + + {schema.additionalItems && schema.additionalItems !== true && ( + <> + Additional Items + + + )} + + ); +} + +function isRequired(name: string, required?: boolean | string[]) { + if (required === true) { + return true; + } + if (Array.isArray(required)) { + return required.includes(name); + } + return false; +} + +function ObjectView({ path, depth, schema }: SchemaViewProps) { + const properties = Object.entries(schema.properties ?? {}); + const patternProperties = Object.entries(schema.patternProperties ?? {}); + + return ( + <> + {depth > 0 && ( + + {schema.description && ( + + {schema.description} + + )} + + + )} + {properties.length > 0 && ( + <> + {depth > 0 && Properties} + {properties.map(([name, propSchema], index) => ( + + ))} + + )} + {patternProperties.length > 0 && ( + <> + {depth > 0 && ( + Pattern Properties + )} + {patternProperties.map(([name, propSchema], index) => ( + ` : name} + depth={depth + 1} + schema={propSchema} + lastChild={index === patternProperties.length - 1} + required={isRequired(name, schema.required)} + /> + ))} + + )} + {schema.additionalProperties && schema.additionalProperties !== true && ( + <> + Additional Properties + + + )} + + ); +} + +interface MetadataViewRowProps { + label: string; + text?: string; + data?: JsonValue; +} + +function titleVariant(depth: number) { + if (depth <= 1) { + return 'h2'; + } else if (depth === 2) { + return 'h3'; + } else if (depth === 3) { + return 'h4'; + } else if (depth === 4) { + return 'h5'; + } + return 'h6'; +} + +const useChildViewStyles = makeStyles(theme => ({ + title: { + marginBottom: 0, + }, + chip: { + marginLeft: theme.spacing(1), + marginRight: 0, + marginBottom: 0, + }, +})); + +function ChildView({ + path, + depth, + schema, + required, + lastChild, +}: { + path: string; + depth: number; + schema?: Schema; + required?: boolean; + lastChild?: boolean; +}) { + const classes = useChildViewStyles(); + const titleRef = useRef(null); + const scroll = useScrollTargets(); + + useEffect(() => { + return scroll?.setScrollListener(path, () => { + titleRef.current?.scrollIntoView({ behavior: 'smooth' }); + }); + }, [scroll, path]); + + const chips = new Array(); + const chipProps = { size: 'small' as const, classes: { root: classes.chip } }; + + if (required) { + chips.push( + , + ); + } + + const visibility = (schema as { visibility?: string })?.visibility; + if (visibility === 'frontend') { + chips.push( + , + ); + } else if (visibility === 'secret') { + chips.push( + , + ); + } + + return ( + + + + + + {path} + + {chips.length > 0 && } + {chips} + + {schema && ( + + )} + + + ); +} + +function MatchView({ + path, + depth, + schema, + label, +}: { + path: string; + depth: number; + schema: Schema[]; + label: string; +}) { + return ( + <> + {label} + {schema.map((optionSchema, index) => ( + + ))} + + ); +} + +function ScalarView({ schema }: SchemaViewProps) { + return ( + <> + {schema.description && ( + + {schema.description} + + )} + + + ); +} + +interface MetadataViewRowProps { + label: string; + text?: string; + data?: JsonValue; +} + +function MetadataViewRow({ label, text, data }: MetadataViewRowProps) { + if (text === undefined && data === undefined) { + return null; + } + return ( + + + + {label} + + + + + {data ? JSON.stringify(data) : text} + + + + ); +} + +function MetadataView({ schema }: { schema: Schema }) { + return ( + + + + + + {schema.additionalProperties === true && ( + + )} + {schema.additionalItems === true && ( + + )} + + + + + + + + + + + + + + + +
+
+ ); +} diff --git a/plugins/devtools-backend/CHANGELOG.md b/plugins/devtools-backend/CHANGELOG.md index 740e03554c..a634afb3da 100644 --- a/plugins/devtools-backend/CHANGELOG.md +++ b/plugins/devtools-backend/CHANGELOG.md @@ -1,5 +1,73 @@ # @backstage/plugin-devtools-backend +## 0.5.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/config-loader@1.9.3-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.14-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.5.0-next.1 + +### Minor Changes + +- c781a9a: **BREAKING** Removed support for what is known as the legacy backend, please use the New Backend System. + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/config-loader@1.9.3-next.0 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-common@0.8.2 + +## 0.4.3-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/cli-common@0.1.15 + - @backstage/config@1.3.0 + - @backstage/config-loader@1.9.2 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 0.4.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/config-loader@1.9.2 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/cli-common@0.1.15 + - @backstage/errors@1.2.5 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-node@0.8.5 + ## 0.4.2-next.2 ### Patch Changes diff --git a/plugins/devtools-backend/README.md b/plugins/devtools-backend/README.md index d9ffb3e076..13e749e8e3 100644 --- a/plugins/devtools-backend/README.md +++ b/plugins/devtools-backend/README.md @@ -25,54 +25,6 @@ Here's how to get the DevTools Backend up and running in the new backend system: 3. Now run `yarn start-backend` from the repo root 4. Finally open `http://localhost:7007/api/devtools/health` in a browser and it should return `{"status":"ok"}` -## Old Backend System - -If you are still on the old backend system, please consider migrating to the new backend system. But to install this plugin in an old backend, see below. - -1. First we need to add the `@backstage/plugin-devtools-backend` package to your backend: - - ```sh - # From the Backstage root directory - yarn --cwd packages/backend add @backstage/plugin-devtools-backend - ``` - -2. Then we will create a new file named `packages/backend/src/plugins/devtools.ts`, and add the - following to it: - - ```ts - import { createRouter } from '@backstage/plugin-devtools-backend'; - import { Router } from 'express'; - import type { PluginEnvironment } from '../types'; - - export default function createPlugin( - env: PluginEnvironment, - ): Promise { - return createRouter({ - logger: env.logger, - config: env.config, - permissions: env.permissions, - discovery: env.discovery, - }); - } - ``` - -3. Next we wire this into the overall backend router, edit `packages/backend/src/index.ts`: - - ```ts - import devTools from './plugins/devtools'; - // ... - async function main() { - // ... - // Add this line under the other lines that follow the useHotMemoize pattern - const devToolsEnv = useHotMemoize(module, () => createEnv('devtools')); - // ... - // Insert this line under the other lines that add their routers to apiRouter in the same way - apiRouter.use('/devtools', await devTools(devToolsEnv)); - ``` - -4. Now run `yarn start-backend` from the repo root -5. Finally open `http://localhost:7007/api/devtools/health` in a browser and it should return `{"status":"ok"}` - ## Links - [Frontend part of the plugin](https://github.com/backstage/backstage/tree/master/plugins/devtools) diff --git a/plugins/devtools-backend/package.json b/plugins/devtools-backend/package.json index e59a1c6df4..68c3f78e60 100644 --- a/plugins/devtools-backend/package.json +++ b/plugins/devtools-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-backend", - "version": "0.4.2-next.2", + "version": "0.5.0-next.2", "backstage": { "role": "backend-plugin", "pluginId": "devtools", @@ -38,7 +38,7 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-common": "^0.25.0", + "@backstage/backend-defaults": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/cli-common": "workspace:^", "@backstage/config": "workspace:^", @@ -49,14 +49,12 @@ "@backstage/plugin-permission-node": "workspace:^", "@backstage/types": "workspace:^", "@manypkg/get-packages": "^1.1.3", - "@types/express": "*", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0", "express": "^4.18.1", "express-promise-router": "^4.1.0", "fs-extra": "^11.0.0", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "ping": "^0.4.1", "semver": "^7.5.3", "yn": "^4.0.0" @@ -65,6 +63,7 @@ "@backstage/backend-defaults": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", + "@types/express": "^4.17.6", "@types/ping": "^0.4.1", "@types/supertest": "^2.0.8", "@types/yarnpkg__lockfile": "^1.1.4", diff --git a/plugins/devtools-backend/report.api.md b/plugins/devtools-backend/report.api.md index 5fceda3d46..d4830e7a7b 100644 --- a/plugins/devtools-backend/report.api.md +++ b/plugins/devtools-backend/report.api.md @@ -7,16 +7,8 @@ import { BackendFeature } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; import { ConfigInfo } from '@backstage/plugin-devtools-common'; import { DevToolsInfo } from '@backstage/plugin-devtools-common'; -import { DiscoveryService } from '@backstage/backend-plugin-api'; -import express from 'express'; import { ExternalDependency } from '@backstage/plugin-devtools-common'; -import { HttpAuthService } from '@backstage/backend-plugin-api'; import { LoggerService } from '@backstage/backend-plugin-api'; -import { PermissionsService } from '@backstage/backend-plugin-api'; -import { RootConfigService } from '@backstage/backend-plugin-api'; - -// @public @deprecated (undocumented) -export function createRouter(options: RouterOptions): Promise; // @public (undocumented) export class DevToolsBackendApi { @@ -32,20 +24,4 @@ export class DevToolsBackendApi { // @public const devtoolsPlugin: BackendFeature; export default devtoolsPlugin; - -// @public @deprecated (undocumented) -export interface RouterOptions { - // (undocumented) - config: RootConfigService; - // (undocumented) - devToolsBackendApi?: DevToolsBackendApi; - // (undocumented) - discovery: DiscoveryService; - // (undocumented) - httpAuth?: HttpAuthService; - // (undocumented) - logger: LoggerService; - // (undocumented) - permissions: PermissionsService; -} ``` diff --git a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts index ae687f3cb0..5ecc3327e0 100644 --- a/plugins/devtools-backend/src/api/DevToolsBackendApi.ts +++ b/plugins/devtools-backend/src/api/DevToolsBackendApi.ts @@ -24,9 +24,7 @@ import { ExternalDependencyStatus, PackageDependency, } from '@backstage/plugin-devtools-common'; - import { JsonObject } from '@backstage/types'; -import fetch from 'node-fetch'; import { findPaths } from '@backstage/cli-common'; import { getPackages } from '@manypkg/get-packages'; import ping from 'ping'; diff --git a/plugins/devtools-backend/src/index.ts b/plugins/devtools-backend/src/index.ts index 58d4570163..3c73ef0e19 100644 --- a/plugins/devtools-backend/src/index.ts +++ b/plugins/devtools-backend/src/index.ts @@ -21,5 +21,4 @@ */ export { DevToolsBackendApi } from './api'; -export * from './service/router'; export { devtoolsPlugin as default } from './plugin'; diff --git a/plugins/devtools-backend/src/service/router.test.ts b/plugins/devtools-backend/src/service/router.test.ts index 9f9db0a8d4..a530f82adc 100644 --- a/plugins/devtools-backend/src/service/router.test.ts +++ b/plugins/devtools-backend/src/service/router.test.ts @@ -51,6 +51,7 @@ describe('createRouter', () => { }), discovery: mockServices.discovery(), permissions: permissionEvaluator, + httpAuth: mockServices.httpAuth(), }); app = express().use(router); }); diff --git a/plugins/devtools-backend/src/service/router.ts b/plugins/devtools-backend/src/service/router.ts index e3eb72c293..adcb79c4cd 100644 --- a/plugins/devtools-backend/src/service/router.ts +++ b/plugins/devtools-backend/src/service/router.ts @@ -24,10 +24,6 @@ import { import { DevToolsBackendApi } from '../api'; import { NotAllowedError } from '@backstage/errors'; import Router from 'express-promise-router'; -import { - createLegacyAuthAdapters, - errorHandler, -} from '@backstage/backend-common'; import express from 'express'; import { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node'; import { @@ -37,10 +33,10 @@ import { PermissionsService, RootConfigService, } from '@backstage/backend-plugin-api'; +import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter'; /** - * @public - * @deprecated Please migrate to the new backend system as this will be removed in the future. + * @internal */ export interface RouterOptions { devToolsBackendApi?: DevToolsBackendApi; @@ -48,19 +44,16 @@ export interface RouterOptions { config: RootConfigService; permissions: PermissionsService; discovery: DiscoveryService; - httpAuth?: HttpAuthService; + httpAuth: HttpAuthService; } /** - * @deprecated Please migrate to the new backend system as this will be removed in the future. - * @public + * @internal * */ export async function createRouter( options: RouterOptions, ): Promise { - const { logger, config, permissions } = options; - - const { httpAuth } = createLegacyAuthAdapters(options); + const { logger, config, permissions, httpAuth } = options; const devToolsBackendApi = options.devToolsBackendApi || new DevToolsBackendApi(logger, config); @@ -128,6 +121,8 @@ export async function createRouter( response.status(200).json(health); }); - router.use(errorHandler()); + const middleware = MiddlewareFactory.create({ logger, config }); + + router.use(middleware.error()); return router; } diff --git a/plugins/devtools-common/CHANGELOG.md b/plugins/devtools-common/CHANGELOG.md index 5cc72c62ae..719d0a5dbc 100644 --- a/plugins/devtools-common/CHANGELOG.md +++ b/plugins/devtools-common/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-devtools-common +## 0.1.14-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.1.13 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + ## 0.1.12 ### Patch Changes diff --git a/plugins/devtools-common/package.json b/plugins/devtools-common/package.json index 5a14202649..713f515400 100644 --- a/plugins/devtools-common/package.json +++ b/plugins/devtools-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools-common", - "version": "0.1.12", + "version": "0.1.14-next.0", "description": "Common functionalities for the devtools plugin", "backstage": { "role": "common-library", diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md index 61635a6d76..8aac4d63cb 100644 --- a/plugins/devtools/CHANGELOG.md +++ b/plugins/devtools/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-devtools +## 0.1.22-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-devtools-common@0.1.14-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + +## 0.1.22-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + +## 0.1.22-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + +## 0.1.20 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-devtools-common@0.1.13 + - @backstage/plugin-permission-react@0.4.28 + ## 0.1.20-next.2 ### Patch Changes diff --git a/plugins/devtools/package.json b/plugins/devtools/package.json index 6cedae4cc3..c1ea874878 100644 --- a/plugins/devtools/package.json +++ b/plugins/devtools/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-devtools", - "version": "0.1.20-next.2", + "version": "0.1.22-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "devtools", diff --git a/plugins/devtools/report-alpha.api.md b/plugins/devtools/report-alpha.api.md index 1b026d1f78..e3261e0f05 100644 --- a/plugins/devtools/report-alpha.api.md +++ b/plugins/devtools/report-alpha.api.md @@ -19,21 +19,6 @@ const _default: FrontendPlugin< }, {}, { - 'api:devtools': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'page:devtools': ExtensionDefinition<{ kind: 'page'; name: undefined; @@ -85,6 +70,21 @@ const _default: FrontendPlugin< routeRef: RouteRef; }; }>; + 'api:devtools': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; } >; export default _default; diff --git a/plugins/events-backend-module-aws-sqs/CHANGELOG.md b/plugins/events-backend-module-aws-sqs/CHANGELOG.md index 103bc17521..72260d13e4 100644 --- a/plugins/events-backend-module-aws-sqs/CHANGELOG.md +++ b/plugins/events-backend-module-aws-sqs/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-events-backend-module-aws-sqs +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.4.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## 0.4.5 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + ## 0.4.5-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-aws-sqs/config.d.ts b/plugins/events-backend-module-aws-sqs/config.d.ts index c2edfeae8e..f5a9457c82 100644 --- a/plugins/events-backend-module-aws-sqs/config.d.ts +++ b/plugins/events-backend-module-aws-sqs/config.d.ts @@ -48,12 +48,12 @@ export interface Config { /** * (Optional) Visibility timeout for messages in flight. */ - visibilityTimeout: HumanDuration; + visibilityTimeout: HumanDuration | string; /** * (Optional) Wait time when polling for available messages. * Default: 20 seconds. */ - waitTime: HumanDuration; + waitTime: HumanDuration | string; }; /** * (Optional) Timeout for the task execution which includes polling for messages @@ -62,12 +62,12 @@ export interface Config { * * Must be greater than `queue.waitTime` + `waitTimeAfterEmptyReceive`. */ - timeout: HumanDuration; + timeout: HumanDuration | string; /** * (Optional) Wait time before polling again if no message was received. * Default: 1 minute. */ - waitTimeAfterEmptyReceive: HumanDuration; + waitTimeAfterEmptyReceive: HumanDuration | string; }; }; }; diff --git a/plugins/events-backend-module-aws-sqs/package.json b/plugins/events-backend-module-aws-sqs/package.json index 50d67fa739..dd051c85bd 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.5-next.3", + "version": "0.4.6-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-module-aws-sqs/src/publisher/config.ts b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts index 7bad1e38d1..fb553fde40 100644 --- a/plugins/events-backend-module-aws-sqs/src/publisher/config.ts +++ b/plugins/events-backend-module-aws-sqs/src/publisher/config.ts @@ -14,8 +14,8 @@ * limitations under the License. */ -import { Config } from '@backstage/config'; -import { HumanDuration, JsonObject } from '@backstage/types'; +import { Config, readDurationFromConfig } from '@backstage/config'; +import { HumanDuration } from '@backstage/types'; import { Duration } from 'luxon'; const CONFIG_PREFIX_MODULE = 'events.modules.awsSqs.'; @@ -39,7 +39,7 @@ function readOptionalHumanDuration( config: Config, key: string, ): HumanDuration | undefined { - return config.getOptional(key) as HumanDuration; + return config.has(key) ? readDurationFromConfig(config, { key }) : undefined; } function readOptionalDuration( diff --git a/plugins/events-backend-module-azure/CHANGELOG.md b/plugins/events-backend-module-azure/CHANGELOG.md index fe75c3789e..a1072f96f3 100644 --- a/plugins/events-backend-module-azure/CHANGELOG.md +++ b/plugins/events-backend-module-azure/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-azure +## 0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## 0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.14-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-azure/package.json b/plugins/events-backend-module-azure/package.json index 66c26e8b12..2164f96939 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.14-next.3", + "version": "0.2.15-next.2", "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 e06742b466..1c363bdf7d 100644 --- a/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/events-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-bitbucket-cloud +## 0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## 0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.14-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-bitbucket-cloud/package.json b/plugins/events-backend-module-bitbucket-cloud/package.json index 4f1432cc8d..2d6b86abba 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.14-next.3", + "version": "0.2.15-next.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 f0ba9a9984..37fbc34575 100644 --- a/plugins/events-backend-module-gerrit/CHANGELOG.md +++ b/plugins/events-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,37 @@ # @backstage/plugin-events-backend-module-gerrit +## 0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + +## 0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.14-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-gerrit/package.json b/plugins/events-backend-module-gerrit/package.json index c07dbfa29e..5cfd52ee0a 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.14-next.3", + "version": "0.2.15-next.2", "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 449f156a43..8cf4a05752 100644 --- a/plugins/events-backend-module-github/CHANGELOG.md +++ b/plugins/events-backend-module-github/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-events-backend-module-github +## 0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + +## 0.2.14 + +### Patch Changes + +- 9816f51: Fix the event request validation for incoming requests for GitHub webhook events + by using the raw body when verifying the signature. +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.14-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-github/package.json b/plugins/events-backend-module-github/package.json index aad95a3bd9..17a920bc3c 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.2.14-next.3", + "version": "0.2.15-next.2", "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 9ed59739d6..33c97e2ba3 100644 --- a/plugins/events-backend-module-gitlab/CHANGELOG.md +++ b/plugins/events-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-events-backend-module-gitlab +## 0.2.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.2.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.2.15-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/config@1.3.0 + +## 0.2.14 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/backend-plugin-api@1.0.2 + ## 0.2.14-next.3 ### Patch Changes diff --git a/plugins/events-backend-module-gitlab/package.json b/plugins/events-backend-module-gitlab/package.json index 17342d732b..3c28a76c43 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.2.14-next.3", + "version": "0.2.15-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "events", diff --git a/plugins/events-backend-test-utils/CHANGELOG.md b/plugins/events-backend-test-utils/CHANGELOG.md index 25dff00dfe..f219442710 100644 --- a/plugins/events-backend-test-utils/CHANGELOG.md +++ b/plugins/events-backend-test-utils/CHANGELOG.md @@ -1,5 +1,33 @@ # @backstage/plugin-events-backend-test-utils +## 0.1.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.2 + +## 0.1.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.1.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.6-next.0 + +## 0.1.38 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-events-node@0.4.5 + ## 0.1.38-next.3 ### Patch Changes diff --git a/plugins/events-backend-test-utils/package.json b/plugins/events-backend-test-utils/package.json index c2efbdc33a..d6c40af29f 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.38-next.3", + "version": "0.1.39-next.2", "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 c3652b03a7..fe8e168607 100644 --- a/plugins/events-backend/CHANGELOG.md +++ b/plugins/events-backend/CHANGELOG.md @@ -1,5 +1,68 @@ # @backstage/plugin-events-backend +## 0.4.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.4.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-events-node@0.4.6-next.1 + +## 0.3.17-next.0 + +### Patch Changes + +- 1577511: Allow configuring a timeout for event bus polling requests. This can be set like so in your app-config: + + ```yaml + events: + notifyTimeoutMs: 30000 + ``` + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.16 + +### Patch Changes + +- e02a02b: Fix `events.useEventBus` by propagating config to `DefaultEventsService` +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. +- b7d0334: Cleaning up event subscriptions after the max age window +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/errors@1.2.5 + ## 0.3.16-next.3 ### Patch Changes diff --git a/plugins/events-backend/config.d.ts b/plugins/events-backend/config.d.ts index 3d26661855..ffeafdcbd5 100644 --- a/plugins/events-backend/config.d.ts +++ b/plugins/events-backend/config.d.ts @@ -16,6 +16,12 @@ export interface Config { events?: { + /** + * Timeout in milliseconds for how long to wait before closing subscription events + * requests to ensure they don't stall or that events get stuck. Defaults to 55 seconds. + */ + notifyTimeoutMs?: number; + http?: { /** * Topics for which a route has to be registered diff --git a/plugins/events-backend/package.json b/plugins/events-backend/package.json index 79a1636f5e..39d6068d3b 100644 --- a/plugins/events-backend/package.json +++ b/plugins/events-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-events-backend", - "version": "0.3.16-next.3", + "version": "0.4.0-next.2", "backstage": { "role": "backend-plugin", "pluginId": "events", diff --git a/plugins/events-backend/src/schema/openapi/generated/apis/Api.server.ts b/plugins/events-backend/src/schema/openapi/generated/apis/Api.server.ts new file mode 100644 index 0000000000..4a1efdfe67 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/apis/Api.server.ts @@ -0,0 +1,59 @@ +/* + * 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. + */ + +// + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { GetSubscriptionEvents200Response } from '../models/GetSubscriptionEvents200Response.model'; +import { PostEventRequest } from '../models/PostEventRequest.model'; +import { PutSubscriptionRequest } from '../models/PutSubscriptionRequest.model'; + +/** + * @public + */ +export type GetSubscriptionEvents = { + path: { + subscriptionId: string; + }; + response: GetSubscriptionEvents200Response | void | Error; +}; +/** + * @public + */ +export type PostEvent = { + body: PostEventRequest; + response: void | void | Error; +}; +/** + * @public + */ +export type PutSubscription = { + path: { + subscriptionId: string; + }; + body: PutSubscriptionRequest; + response: void | Error; +}; + +export type EndpointMap = { + '#get|/bus/v1/subscriptions/{subscriptionId}/events': GetSubscriptionEvents; + + '#post|/bus/v1/events': PostEvent; + + '#put|/bus/v1/subscriptions/{subscriptionId}': PutSubscription; +}; diff --git a/plugins/events-backend/src/schema/openapi/generated/apis/index.ts b/plugins/events-backend/src/schema/openapi/generated/apis/index.ts new file mode 100644 index 0000000000..a3cdbbebd2 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/apis/index.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ + +// + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +export * from './Api.server'; diff --git a/plugins/events-backend/src/schema/openapi/generated/index.ts b/plugins/events-backend/src/schema/openapi/generated/index.ts new file mode 100644 index 0000000000..69c39313c6 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export * from './apis'; +export * from './router'; diff --git a/plugins/events-backend/src/schema/openapi/generated/models/ErrorError.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..0a51c67fef --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/ErrorError.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorError { + name: string; + message: string; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..d44dcb66d9 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/ErrorRequest.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..91c120483d --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/ErrorResponse.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorResponse { + statusCode: number; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/Event.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/Event.model.ts new file mode 100644 index 0000000000..edd88b0738 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/Event.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Event { + /** + * The topic that the event is published on + */ + topic: string; + /** + * The event payload + */ + payload: any | null; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts new file mode 100644 index 0000000000..3ca3282f47 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Event } from '../models/Event.model'; + +/** + * @public + */ +export interface GetSubscriptionEvents200Response { + events: Array; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/ModelError.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..3e6af947ec --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/ModelError.model.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +/** + * @public + */ +export interface ModelError { + error: ErrorError; + request: ErrorRequest; + response: ErrorResponse; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/PostEventRequest.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/PostEventRequest.model.ts new file mode 100644 index 0000000000..cfaf66ce4f --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/PostEventRequest.model.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Event } from '../models/Event.model'; + +/** + * @public + */ +export interface PostEventRequest { + event: Event; + /** + * The IDs of subscriptions that have already received this event + */ + notifiedSubscribers?: Array; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts b/plugins/events-backend/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts new file mode 100644 index 0000000000..a1dc298789 --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface PutSubscriptionRequest { + /** + * The topics to subscribe to + */ + topics: Array; +} diff --git a/plugins/events-backend/src/schema/openapi/generated/models/index.ts b/plugins/events-backend/src/schema/openapi/generated/models/index.ts new file mode 100644 index 0000000000..5044f65fff --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/generated/models/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export * from '../models/ErrorError.model'; +export * from '../models/ErrorRequest.model'; +export * from '../models/ErrorResponse.model'; +export * from '../models/Event.model'; +export * from '../models/GetSubscriptionEvents200Response.model'; +export * from '../models/ModelError.model'; +export * from '../models/PostEventRequest.model'; +export * from '../models/PutSubscriptionRequest.model'; diff --git a/plugins/events-backend/src/schema/openapi.generated.ts b/plugins/events-backend/src/schema/openapi/generated/router.ts similarity index 95% rename from plugins/events-backend/src/schema/openapi.generated.ts rename to plugins/events-backend/src/schema/openapi/generated/router.ts index 8f8d6c6a82..3c43880170 100644 --- a/plugins/events-backend/src/schema/openapi.generated.ts +++ b/plugins/events-backend/src/schema/openapi/generated/router.ts @@ -17,7 +17,8 @@ // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** -import { createValidatedOpenApiRouter } from '@backstage/backend-openapi-utils'; +import { createValidatedOpenApiRouterFromGeneratedEndpointMap } from '@backstage/backend-openapi-utils'; +import { EndpointMap } from './'; export const spec = { openapi: '3.0.3', @@ -287,5 +288,11 @@ export const spec = { }, } as const; export const createOpenApiRouter = async ( - options?: Parameters['1'], -) => createValidatedOpenApiRouter(spec, options); + options?: Parameters< + typeof createValidatedOpenApiRouterFromGeneratedEndpointMap + >['1'], +) => + createValidatedOpenApiRouterFromGeneratedEndpointMap( + spec, + options, + ); diff --git a/plugins/events-backend/src/schema/openapi/index.ts b/plugins/events-backend/src/schema/openapi/index.ts new file mode 100644 index 0000000000..db98243cbf --- /dev/null +++ b/plugins/events-backend/src/schema/openapi/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './generated'; diff --git a/plugins/events-backend/src/service/EventsPlugin.ts b/plugins/events-backend/src/service/EventsPlugin.ts index 89f50d835b..a837e69c32 100644 --- a/plugins/events-backend/src/service/EventsPlugin.ts +++ b/plugins/events-backend/src/service/EventsPlugin.ts @@ -113,6 +113,10 @@ export const eventsPlugin = createBackendPlugin({ // that is used there as part of the middleware stack. httpRouter.use(eventsRouter); + const notifyTimeoutMs = config.getOptionalNumber( + 'events.notifyTimeoutMs', + ); + httpRouter.use( await createEventBusRouter({ database, @@ -120,6 +124,7 @@ export const eventsPlugin = createBackendPlugin({ logger, httpAuth, scheduler, + notifyTimeoutMs, }), ); diff --git a/plugins/events-backend/src/service/hub/createEventBusRouter.ts b/plugins/events-backend/src/service/hub/createEventBusRouter.ts index 4a332d5ce5..e8dc8ef113 100644 --- a/plugins/events-backend/src/service/hub/createEventBusRouter.ts +++ b/plugins/events-backend/src/service/hub/createEventBusRouter.ts @@ -22,11 +22,14 @@ import { SchedulerService, } from '@backstage/backend-plugin-api'; import { Handler } from 'express'; -import { createOpenApiRouter } from '../../schema/openapi.generated'; +import { createOpenApiRouter } from '../../schema/openapi'; import { MemoryEventBusStore } from './MemoryEventBusStore'; import { DatabaseEventBusStore } from './DatabaseEventBusStore'; import { EventBusStore } from './types'; -import { EventParams } from '@backstage/plugin-events-node'; +import { + EVENTS_NOTIFY_TIMEOUT_HEADER, + EventParams, +} from '@backstage/plugin-events-node'; const DEFAULT_NOTIFY_TIMEOUT_MS = 55_000; // Just below 60s, which is a common HTTP timeout @@ -229,6 +232,10 @@ export async function createEventBusRouter(options: { })), }); } else { + res.setHeader( + EVENTS_NOTIFY_TIMEOUT_HEADER, + notifyTimeoutMs.toString(), + ); res.status(202); res.flushHeaders(); diff --git a/plugins/events-node/CHANGELOG.md b/plugins/events-node/CHANGELOG.md index f3a6798091..a1d6a6114e 100644 --- a/plugins/events-node/CHANGELOG.md +++ b/plugins/events-node/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-events-node +## 0.4.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/types@1.2.0 + +## 0.4.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.4.6-next.0 + +### Patch Changes + +- 79a06f6: Clarified purpose of subscriber ID in TSDoc for `EventsServiceSubscribeOptions`. +- 1577511: Allow configuring a timeout for event bus polling requests. This can be set like so in your app-config: + + ```yaml + events: + notifyTimeoutMs: 30000 + ``` + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.4.5 + +### Patch Changes + +- 4501631: Fixed an issue where subscribing to events threw an error and gave up too easily. Calling the subscribe method will cause the background polling loop to keep trying to connect to the events backend, even if the initial request fails. + + By default the events service will attempt to publish and subscribe to events from the events bus API in the events backend, but if it fails due to the events backend not being installed, it will bail and never try calling the API again. There is now a new `events.useEventBus` configuration and option for the `DefaultEventsService` that lets you control this behavior. You can set it to `'never'` to disabled API calls to the events backend completely, or `'always'` to never allow it to be disabled. + +- e02a02b: Fix `events.useEventBus` by propagating config to `DefaultEventsService` +- 9816f51: Add raw body information to `RequestDetails` + and use the raw body when validating incoming event requests. +- 5d74716: Remove unused backend-common dependency +- 0b57aa1: Fixed an issue where the event bus polling would duplicate and increase exponentially over time. +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 0.4.5-next.3 ### Patch Changes diff --git a/plugins/events-node/package.json b/plugins/events-node/package.json index 0c6bcad752..62653d2966 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.5-next.3", + "version": "0.4.6-next.2", "description": "The plugin-events-node module for @backstage/plugin-events-backend", "backstage": { "role": "node-library", diff --git a/plugins/events-node/report.api.md b/plugins/events-node/report.api.md index 0b9c31090a..f53bb251ec 100644 --- a/plugins/events-node/report.api.md +++ b/plugins/events-node/report.api.md @@ -74,6 +74,9 @@ export abstract class EventRouter { subscribe(): Promise; } +// @public (undocumented) +export const EVENTS_NOTIFY_TIMEOUT_HEADER = 'backstage-events-notify-timeout'; + // @public export interface EventsService { publish(params: EventParams): Promise; diff --git a/plugins/events-node/src/api/DefaultEventsService.test.ts b/plugins/events-node/src/api/DefaultEventsService.test.ts index a7fc7ba50b..13a6a68fa4 100644 --- a/plugins/events-node/src/api/DefaultEventsService.test.ts +++ b/plugins/events-node/src/api/DefaultEventsService.test.ts @@ -16,6 +16,7 @@ import { DefaultEventsService } from './DefaultEventsService'; import { EventParams } from './EventParams'; +import { EVENTS_NOTIFY_TIMEOUT_HEADER } from './EventsService'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { @@ -248,6 +249,101 @@ describe('DefaultEventsService', () => { blockingController!.close(); }); + it('should timeout polling if the response has a timeout header', async () => { + const logger = mockServices.logger.mock(); + const service = DefaultEventsService.create({ logger }).forPlugin('a', { + auth: mockServices.auth(), + logger, + discovery: mockServices.discovery(), + lifecycle: mockServices.lifecycle.mock(), + }); + + let callCount = 0; + + let blockingController: ReadableStreamDefaultController; + const blockingStream = new ReadableStream({ + start(controller) { + blockingController = controller; + }, + }); + + mswServer.use( + rest.put( + 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester', + (_req, res, ctx) => res(ctx.status(200)), + ), + // The first and third calls result in a blocking 202 that is resolved after 100ms + // The second and fourth calls result in a 200 with an event + // The fifth call blocks until the end of the test + // No more than 5 calls should be made + rest.get( + 'http://localhost:0/api/events/bus/v1/subscriptions/a.tester/events', + (_req, res, ctx) => { + callCount += 1; + if (callCount === 1 || callCount === 3) { + return res( + ctx.status(202), + ctx.body( + new ReadableStream({ + start(controller) { + setTimeout(() => controller.close(), 100); + }, + }), + ), + ); + } else if (callCount === 2 || callCount === 4) { + return res( + ctx.status(200), + ctx.json({ + events: [{ topic: 'test', payload: { callCount } }], + }), + ); + } else if (callCount === 5) { + // 5th call has a timeout header so polling should proceed to the next call + return res( + ctx.set(EVENTS_NOTIFY_TIMEOUT_HEADER, '100'), + ctx.status(202), + ctx.body(blockingStream), + ); + } else if (callCount === 6) { + return res(ctx.status(202), ctx.body(blockingStream)); + } + throw new Error(`events endpoint called too many times`); + }, + ), + ); + + const event = await new Promise(resolve => { + const events = new Array(); + service.subscribe({ + id: 'tester', + topics: ['test'], + async onEvent(newEvent) { + events.push(newEvent); + if (events.length === 2) { + resolve(events); + } + }, + }); + }); + + expect(event).toEqual([ + { topic: 'test', eventPayload: { callCount: 2 } }, + { topic: 'test', eventPayload: { callCount: 4 } }, + ]); + + // Wait to allow timeout to trigger and make sure no additional calls happen + await new Promise(resolve => setTimeout(resolve, 2000)); + + expect(callCount).toBe(6); + + // Internal call to clean up subscriptions + await (service as any).shutdown(); + + // Close the stream for the 5th call so that we don't leave the request hanging + blockingController!.close(); + }); + it('should not read events from bus if disabled', async () => { const logger = mockServices.logger.mock(); const service = DefaultEventsService.create({ diff --git a/plugins/events-node/src/api/DefaultEventsService.ts b/plugins/events-node/src/api/DefaultEventsService.ts index 7a35ed305a..3ceed45a26 100644 --- a/plugins/events-node/src/api/DefaultEventsService.ts +++ b/plugins/events-node/src/api/DefaultEventsService.ts @@ -22,7 +22,11 @@ import { RootConfigService, } from '@backstage/backend-plugin-api'; import { EventParams } from './EventParams'; -import { EventsService, EventsServiceSubscribeOptions } from './EventsService'; +import { + EVENTS_NOTIFY_TIMEOUT_HEADER, + EventsService, + EventsServiceSubscribeOptions, +} from './EventsService'; import { DefaultApiClient } from '../generated'; import { ResponseError } from '@backstage/errors'; @@ -214,10 +218,28 @@ class PluginEventsService implements EventsService { // immediately again lock.release(); - // We don't actually expect any response body here, but waiting for - // an empty body to be returned has been more reliable that waiting - // for the response body stream to close. - await res.text(); + + const notifyTimeoutHeader = res.headers.get( + EVENTS_NOTIFY_TIMEOUT_HEADER, + ); + + // Add 1s to the timeout to allow the server to potentially timeout first + const notifyTimeoutMs = + notifyTimeoutHeader && !isNaN(parseInt(notifyTimeoutHeader, 10)) + ? Number(notifyTimeoutHeader) + 1_000 + : null; + + await Promise.race( + [ + // We don't actually expect any response body here, but waiting for + // an empty body to be returned has been more reliable that waiting + // for the response body stream to close. + res.text(), + notifyTimeoutMs + ? new Promise(resolve => setTimeout(resolve, notifyTimeoutMs)) + : null, + ].filter(Boolean), + ); } else if (res.status === 200) { const data = await res.json(); if (data) { diff --git a/plugins/events-node/src/api/EventsService.ts b/plugins/events-node/src/api/EventsService.ts index 7af13f9b07..6547ea9889 100644 --- a/plugins/events-node/src/api/EventsService.ts +++ b/plugins/events-node/src/api/EventsService.ts @@ -44,7 +44,7 @@ export interface EventsService { */ export type EventsServiceSubscribeOptions = { /** - * Identifier for the subscription. E.g., used as part of log messages. + * Subscriber ID that is scoped to the calling plugin. Subscribers with the same ID will have events distributed between them. */ id: string; topics: string[]; @@ -55,3 +55,8 @@ export type EventsServiceSubscribeOptions = { * @public */ export type EventsServiceEventHandler = (params: EventParams) => Promise; + +/** + * @public + */ +export const EVENTS_NOTIFY_TIMEOUT_HEADER = 'backstage-events-notify-timeout'; diff --git a/plugins/events-node/src/api/index.ts b/plugins/events-node/src/api/index.ts index 6f3817cedc..ef2946396c 100644 --- a/plugins/events-node/src/api/index.ts +++ b/plugins/events-node/src/api/index.ts @@ -16,6 +16,7 @@ export type { EventParams } from './EventParams'; export { EventRouter } from './EventRouter'; +export { EVENTS_NOTIFY_TIMEOUT_HEADER } from './EventsService'; export type { EventsService, EventsServiceSubscribeOptions, diff --git a/plugins/events-node/src/schema/openapi/generated/apis/Api.client.ts b/plugins/events-node/src/schema/openapi/generated/apis/Api.client.ts new file mode 100644 index 0000000000..c77ddc1d67 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/apis/Api.client.ts @@ -0,0 +1,163 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { DiscoveryApi } from '../types/discovery'; +import { FetchApi } from '../types/fetch'; +import crossFetch from 'cross-fetch'; +import { pluginId } from '../pluginId'; +import * as parser from 'uri-template'; +import { GetSubscriptionEvents200Response } from '../models/GetSubscriptionEvents200Response.model'; +import { PostEventRequest } from '../models/PostEventRequest.model'; +import { PutSubscriptionRequest } from '../models/PutSubscriptionRequest.model'; + +/** + * Wraps the Response type to convey a type on the json call. + * + * @public + */ +export type TypedResponse = Omit & { + json: () => Promise; +}; + +/** + * Options you can pass into a request for additional information. + * + * @public + */ +export interface RequestOptions { + token?: string; +} +/** + * @public + */ +export type GetSubscriptionEvents = { + path: { + subscriptionId: string; + }; +}; +/** + * @public + */ +export type PostEvent = { + body: PostEventRequest; +}; +/** + * @public + */ +export type PutSubscription = { + path: { + subscriptionId: string; + }; + body: PutSubscriptionRequest; +}; + +/** + * @public + */ +export class DefaultApiClient { + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: { + discoveryApi: { getBaseUrl(pluginId: string): Promise }; + fetchApi?: { fetch: typeof fetch }; + }) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi || { fetch: crossFetch }; + } + + /** + * Get new events for the provided subscription + * @param subscriptionId - + */ + public async getSubscriptionEvents( + // @ts-ignore + request: GetSubscriptionEvents, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/bus/v1/subscriptions/{subscriptionId}/events`; + + const uri = parser.parse(uriTemplate).expand({ + subscriptionId: request.path.subscriptionId, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'GET', + }); + } + + /** + * Publish a new event + * @param postEventRequest - + */ + public async postEvent( + // @ts-ignore + request: PostEvent, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/bus/v1/events`; + + const uri = parser.parse(uriTemplate).expand({}); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'POST', + body: JSON.stringify(request.body), + }); + } + + /** + * Ensures that the subscription exists with the provided configuration + * @param subscriptionId - + * @param putSubscriptionRequest - + */ + public async putSubscription( + // @ts-ignore + request: PutSubscription, + options?: RequestOptions, + ): Promise> { + const baseUrl = await this.discoveryApi.getBaseUrl(pluginId); + + const uriTemplate = `/bus/v1/subscriptions/{subscriptionId}`; + + const uri = parser.parse(uriTemplate).expand({ + subscriptionId: request.path.subscriptionId, + }); + + return await this.fetchApi.fetch(`${baseUrl}${uri}`, { + headers: { + 'Content-Type': 'application/json', + ...(options?.token && { Authorization: `Bearer ${options?.token}` }), + }, + method: 'PUT', + body: JSON.stringify(request.body), + }); + } +} diff --git a/plugins/events-node/src/schema/openapi/generated/apis/index.ts b/plugins/events-node/src/schema/openapi/generated/apis/index.ts new file mode 100644 index 0000000000..af52f9db46 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/apis/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './Api.client'; diff --git a/plugins/events-node/src/schema/openapi/generated/index.ts b/plugins/events-node/src/schema/openapi/generated/index.ts new file mode 100644 index 0000000000..bb399e97a0 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export * from './apis'; +export * from './models'; diff --git a/plugins/events-node/src/schema/openapi/generated/models/ErrorError.model.ts b/plugins/events-node/src/schema/openapi/generated/models/ErrorError.model.ts new file mode 100644 index 0000000000..0a51c67fef --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/ErrorError.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorError { + name: string; + message: string; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/ErrorRequest.model.ts b/plugins/events-node/src/schema/openapi/generated/models/ErrorRequest.model.ts new file mode 100644 index 0000000000..d44dcb66d9 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/ErrorRequest.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorRequest { + method: string; + url: string; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/ErrorResponse.model.ts b/plugins/events-node/src/schema/openapi/generated/models/ErrorResponse.model.ts new file mode 100644 index 0000000000..91c120483d --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/ErrorResponse.model.ts @@ -0,0 +1,26 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface ErrorResponse { + statusCode: number; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/Event.model.ts b/plugins/events-node/src/schema/openapi/generated/models/Event.model.ts new file mode 100644 index 0000000000..edd88b0738 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/Event.model.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface Event { + /** + * The topic that the event is published on + */ + topic: string; + /** + * The event payload + */ + payload: any | null; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts b/plugins/events-node/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts new file mode 100644 index 0000000000..3ca3282f47 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/GetSubscriptionEvents200Response.model.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Event } from '../models/Event.model'; + +/** + * @public + */ +export interface GetSubscriptionEvents200Response { + events: Array; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/ModelError.model.ts b/plugins/events-node/src/schema/openapi/generated/models/ModelError.model.ts new file mode 100644 index 0000000000..3e6af947ec --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/ModelError.model.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { ErrorError } from '../models/ErrorError.model'; +import { ErrorRequest } from '../models/ErrorRequest.model'; +import { ErrorResponse } from '../models/ErrorResponse.model'; + +/** + * @public + */ +export interface ModelError { + error: ErrorError; + request: ErrorRequest; + response: ErrorResponse; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/PostEventRequest.model.ts b/plugins/events-node/src/schema/openapi/generated/models/PostEventRequest.model.ts new file mode 100644 index 0000000000..cfaf66ce4f --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/PostEventRequest.model.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** +import { Event } from '../models/Event.model'; + +/** + * @public + */ +export interface PostEventRequest { + event: Event; + /** + * The IDs of subscriptions that have already received this event + */ + notifiedSubscribers?: Array; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts b/plugins/events-node/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts new file mode 100644 index 0000000000..a1dc298789 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/PutSubscriptionRequest.model.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +/** + * @public + */ +export interface PutSubscriptionRequest { + /** + * The topics to subscribe to + */ + topics: Array; +} diff --git a/plugins/events-node/src/schema/openapi/generated/models/index.ts b/plugins/events-node/src/schema/openapi/generated/models/index.ts new file mode 100644 index 0000000000..5044f65fff --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/models/index.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export * from '../models/ErrorError.model'; +export * from '../models/ErrorRequest.model'; +export * from '../models/ErrorResponse.model'; +export * from '../models/Event.model'; +export * from '../models/GetSubscriptionEvents200Response.model'; +export * from '../models/ModelError.model'; +export * from '../models/PostEventRequest.model'; +export * from '../models/PutSubscriptionRequest.model'; diff --git a/plugins/events-node/src/schema/openapi/generated/pluginId.ts b/plugins/events-node/src/schema/openapi/generated/pluginId.ts new file mode 100644 index 0000000000..36b5433cc3 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/pluginId.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export const pluginId = 'events'; diff --git a/plugins/events-node/src/schema/openapi/generated/types/discovery.ts b/plugins/events-node/src/schema/openapi/generated/types/discovery.ts new file mode 100644 index 0000000000..a7f87d3780 --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/types/discovery.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of the DiscoveryApi, to avoid importing core-plugin-api. + */ +export type DiscoveryApi = { + getBaseUrl(pluginId: string): Promise; +}; diff --git a/plugins/events-node/src/schema/openapi/generated/types/fetch.ts b/plugins/events-node/src/schema/openapi/generated/types/fetch.ts new file mode 100644 index 0000000000..3de56c028e --- /dev/null +++ b/plugins/events-node/src/schema/openapi/generated/types/fetch.ts @@ -0,0 +1,22 @@ +/* + * 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. + */ + +/** + * This is a copy of FetchApi, to avoid importing core-plugin-api. + */ +export type FetchApi = { + fetch: typeof fetch; +}; diff --git a/plugins/events-node/src/schema/openapi/index.ts b/plugins/events-node/src/schema/openapi/index.ts new file mode 100644 index 0000000000..db98243cbf --- /dev/null +++ b/plugins/events-node/src/schema/openapi/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './generated'; diff --git a/plugins/example-todo-list-backend/CHANGELOG.md b/plugins/example-todo-list-backend/CHANGELOG.md index 823987f9c7..16018e8305 100644 --- a/plugins/example-todo-list-backend/CHANGELOG.md +++ b/plugins/example-todo-list-backend/CHANGELOG.md @@ -1,5 +1,41 @@ # @internal/plugin-todo-list-backend +## 1.0.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + +## 1.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/errors@1.2.5 + +## 1.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/errors@1.2.5 + +## 1.0.33 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/errors@1.2.5 + ## 1.0.33-next.2 ### Patch Changes diff --git a/plugins/example-todo-list-backend/package.json b/plugins/example-todo-list-backend/package.json index 9bd55016f5..d6f796625e 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.33-next.2", + "version": "1.0.34-next.2", "backstage": { "role": "backend-plugin", "pluginId": "todo-list", diff --git a/plugins/example-todo-list-common/CHANGELOG.md b/plugins/example-todo-list-common/CHANGELOG.md index 4b1ba3f9ce..ad6b7898a2 100644 --- a/plugins/example-todo-list-common/CHANGELOG.md +++ b/plugins/example-todo-list-common/CHANGELOG.md @@ -1,5 +1,19 @@ # @internal/plugin-todo-list-common +## 1.0.23-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.0.22 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-permission-common@0.8.2 + ## 1.0.21 ### Patch Changes diff --git a/plugins/example-todo-list-common/package.json b/plugins/example-todo-list-common/package.json index 42c83f49d8..a06daec424 100644 --- a/plugins/example-todo-list-common/package.json +++ b/plugins/example-todo-list-common/package.json @@ -1,6 +1,6 @@ { "name": "@internal/plugin-todo-list-common", - "version": "1.0.21", + "version": "1.0.23-next.0", "backstage": { "role": "common-library", "pluginId": "todo-list", diff --git a/plugins/example-todo-list/CHANGELOG.md b/plugins/example-todo-list/CHANGELOG.md index 60d7ec49b9..7bbc9e46a1 100644 --- a/plugins/example-todo-list/CHANGELOG.md +++ b/plugins/example-todo-list/CHANGELOG.md @@ -1,5 +1,37 @@ # @internal/plugin-todo-list +## 1.0.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## 1.0.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + +## 1.0.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## 1.0.33 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + ## 1.0.33-next.2 ### Patch Changes diff --git a/plugins/example-todo-list/package.json b/plugins/example-todo-list/package.json index 8cecb44d05..bc10e46156 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.33-next.2", + "version": "1.0.34-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "todo-list", diff --git a/plugins/home-react/CHANGELOG.md b/plugins/home-react/CHANGELOG.md index 5b96234618..28e6d96519 100644 --- a/plugins/home-react/CHANGELOG.md +++ b/plugins/home-react/CHANGELOG.md @@ -1,5 +1,41 @@ # @backstage/plugin-home-react +## 0.1.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## 0.1.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + +## 0.1.21-next.0 + +### Patch Changes + +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## 0.1.19 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + ## 0.1.19-next.2 ### Patch Changes diff --git a/plugins/home-react/package.json b/plugins/home-react/package.json index 2d579ee0df..c3c93f88f6 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.19-next.2", + "version": "0.1.21-next.2", "description": "A Backstage plugin that contains react components helps you build a home page", "backstage": { "role": "web-library", @@ -46,7 +46,7 @@ "@backstage/core-plugin-api": "workspace:^", "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", - "@rjsf/utils": "5.21.2" + "@rjsf/utils": "5.23.1" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/home/CHANGELOG.md b/plugins/home/CHANGELOG.md index 8a776ad641..0c08fa3175 100644 --- a/plugins/home/CHANGELOG.md +++ b/plugins/home/CHANGELOG.md @@ -1,5 +1,124 @@ # @backstage/plugin-home +## 0.8.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.2 + +## 0.8.3-next.1 + +### Patch Changes + +- 7248f3b: Added a new Quick Start Card to `plugin-home`, which can display basic info to get users the info they need to onboard to the Catalog. + + ``` + import { QuickStartCard } from '@backstage/plugin-home'; + + } + cardDescription="Backstage system model will help you create new entities" + video={ + + } + downloadImage={ + + } + /> + ``` + + See the [storybook examples](https://backstage.io/storybook/?path=/story/plugins-home-components-quickstartcard--default) + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.1 + +## 0.8.3-next.0 + +### Patch Changes + +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/plugin-home-react@0.1.21-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## 0.8.1 + +### Patch Changes + +- 8b1b2cf: Improve Starred Entities UI to reduce whitespace and provide more context on the entities: + + - Use the Entity Presentation API (via ``) to display the entity's name + - Component's `kind` and `spec.type` are displayed as a secondary text + - List items are condensed to reduce unnecessary spacing + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-home-react@0.1.19 + ## 0.8.1-next.3 ### Patch Changes diff --git a/plugins/home/package.json b/plugins/home/package.json index d1189d3047..f7d5f2ff4a 100644 --- a/plugins/home/package.json +++ b/plugins/home/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-home", - "version": "0.8.1-next.3", + "version": "0.8.3-next.2", "description": "A Backstage plugin that helps you build a home page", "backstage": { "role": "frontend-plugin", @@ -70,10 +70,10 @@ "@material-ui/core": "^4.12.2", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", - "@rjsf/core": "5.21.2", - "@rjsf/material-ui": "5.21.2", - "@rjsf/utils": "5.21.2", - "@rjsf/validator-ajv8": "5.21.2", + "@rjsf/core": "5.23.1", + "@rjsf/material-ui": "5.23.1", + "@rjsf/utils": "5.23.1", + "@rjsf/validator-ajv8": "5.23.1", "lodash": "^4.17.21", "luxon": "^3.4.3", "react-grid-layout": "1.3.4", diff --git a/plugins/home/report.api.md b/plugins/home/report.api.md index 023c649ab4..878d8ef646 100644 --- a/plugins/home/report.api.md +++ b/plugins/home/report.api.md @@ -187,6 +187,17 @@ export type LayoutConfiguration = { // @public export type Operators = '<' | '<=' | '==' | '!=' | '>' | '>=' | 'contains'; +// @public +export type QuickStartCardProps = { + modalTitle?: string | React_2.JSX.Element; + docsLinkTitle?: string; + docsLink?: string; + video?: React_2.JSX.Element; + image: React_2.JSX.Element; + cardDescription?: string; + downloadImage?: React_2.JSX.Element; +}; + // @public @deprecated (undocumented) export type RendererProps = RendererProps_2; diff --git a/plugins/home/src/homePageComponents/QuickStart/Content.test.tsx b/plugins/home/src/homePageComponents/QuickStart/Content.test.tsx new file mode 100644 index 0000000000..0acd44768f --- /dev/null +++ b/plugins/home/src/homePageComponents/QuickStart/Content.test.tsx @@ -0,0 +1,69 @@ +/* + * Copyright 2022 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 { Content } from './Content'; +import React from 'react'; +import userEvent from '@testing-library/user-event'; +import { renderInTestApp } from '@backstage/test-utils'; +import ContentImage from './static/backstageSystemModel.png'; + +describe('', () => { + const renderContent = async () => { + return await renderInTestApp( + + } + docsLinkTitle="Testing docs link" + />, + ); + }; + + it('should have expected card content', async () => { + const { getByTestId } = await renderContent(); + const docsLink = getByTestId('quick-start-link-to-docs'); + expect(docsLink).toHaveTextContent('Testing docs link'); + expect(docsLink).toHaveAttribute('target', '_blank'); + }); + + it('clicking the link opens the modal', async () => { + const { getByTestId, getByText } = await renderContent(); + // Find the link element + const link = getByText('Onboarding'); + // Simulate a click event on the link + await userEvent.click(link); + // Assert that the modal is visible + const modal = getByTestId('content-modal-open'); + expect(modal).toBeVisible(); + }); + + it('clicking the image opens the modal', async () => { + const { getByTestId } = await renderContent(); + // Find the link element + const link = getByTestId('quick-start-image'); + // Simulate a click event on the link + await userEvent.click(link); + // Assert that the modal is visible + const modal = getByTestId('content-modal-open'); + expect(modal).toBeVisible(); + }); +}); diff --git a/plugins/home/src/homePageComponents/QuickStart/Content.tsx b/plugins/home/src/homePageComponents/QuickStart/Content.tsx new file mode 100644 index 0000000000..998b1a1798 --- /dev/null +++ b/plugins/home/src/homePageComponents/QuickStart/Content.tsx @@ -0,0 +1,84 @@ +/* + * Copyright 2022 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 React from 'react'; +import { Link } from '@backstage/core-components'; +import Typography from '@material-ui/core/Typography'; +import Grid from '@material-ui/core/Grid'; +import { ContentModal } from './ContentModal'; +import { useStyles } from './styles'; + +/** + * Props customizing the component. + * + * @public + */ +export type QuickStartCardProps = { + /** The modal link title */ + modalTitle?: string | React.JSX.Element; + /** The link to docs title */ + docsLinkTitle?: string; + /** The link to docs */ + docsLink?: string; + /** The video to play on the card */ + video?: React.JSX.Element; + /** A quickstart image to display on the card */ + image: React.JSX.Element; + /** The card description*/ + cardDescription?: string; + /** A component used to download a quickStart image*/ + downloadImage?: React.JSX.Element; +}; + +/** + * A component to display Quick Start info on the homepage. + * + * @public + */ +export const Content = (props: QuickStartCardProps): JSX.Element => { + const styles = useStyles(); + return ( + <> + + + {props.cardDescription || 'Get started with Backstage'} + + + + {props.downloadImage && {props.downloadImage}} + + + {props.docsLinkTitle || 'Learn more'} + + + + {props.video && props.video} + + ); +}; diff --git a/plugins/home/src/homePageComponents/QuickStart/ContentModal.tsx b/plugins/home/src/homePageComponents/QuickStart/ContentModal.tsx new file mode 100644 index 0000000000..a6e000dc42 --- /dev/null +++ b/plugins/home/src/homePageComponents/QuickStart/ContentModal.tsx @@ -0,0 +1,57 @@ +/* + * Copyright 2022 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 React, { useState } from 'react'; +import { Link } from '@backstage/core-components'; +import Modal from '@material-ui/core/Modal'; +import Box from '@material-ui/core/Box'; + +import { useStyles } from './styles'; + +export type ContentModalProps = { + modalContent: React.JSX.Element; + linkContent: string | React.JSX.Element; +}; + +export const ContentModal = (props: ContentModalProps) => { + const { modalContent, linkContent } = props; + const styles = useStyles(); + const [open, setOpen] = useState(false); + + return ( +
+ setOpen(true)} + > + {linkContent} + + setOpen(false)} + aria-labelledby="content-modal" + data-testid="content-modal" + > + + {modalContent} + + +
+ ); +}; diff --git a/plugins/home/src/homePageComponents/QuickStart/QuickStart.stories.tsx b/plugins/home/src/homePageComponents/QuickStart/QuickStart.stories.tsx new file mode 100644 index 0000000000..8d6e6d117e --- /dev/null +++ b/plugins/home/src/homePageComponents/QuickStart/QuickStart.stories.tsx @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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 { QuickStartCard } from '../../plugin'; +import React, { ComponentType, PropsWithChildren } from 'react'; +import { wrapInTestApp } from '@backstage/test-utils'; +import Grid from '@material-ui/core/Grid'; +import ContentImage from './static/backstageSystemModel.png'; + +export default { + title: 'Plugins/Home/Components/QuickStartCard', + decorators: [ + (Story: ComponentType>) => wrapInTestApp(), + ], +}; + +export const Default = () => { + return ( + + + } + /> + + ); +}; + +export const Customized = () => { + return ( + + + } + cardDescription="Backstage system model will help you create new entities" + /> + + ); +}; diff --git a/packages/backend-legacy/src/plugins/devtools.ts b/plugins/home/src/homePageComponents/QuickStart/index.ts similarity index 60% rename from packages/backend-legacy/src/plugins/devtools.ts rename to plugins/home/src/homePageComponents/QuickStart/index.ts index bfa29cd72e..2c2e0ed2f2 100644 --- a/packages/backend-legacy/src/plugins/devtools.ts +++ b/plugins/home/src/homePageComponents/QuickStart/index.ts @@ -14,17 +14,6 @@ * limitations under the License. */ -import { createRouter } from '@backstage/plugin-devtools-backend'; -import { Router } from 'express'; -import type { PluginEnvironment } from '../types'; - -export default async function createPlugin( - env: PluginEnvironment, -): Promise { - return createRouter({ - logger: env.logger, - config: env.config, - permissions: env.permissions, - discovery: env.discovery, - }); -} +export { Content } from './Content'; +export type { QuickStartCardProps } from './Content'; +export type { QuickStartCardClassKey } from './styles'; diff --git a/plugins/home/src/homePageComponents/QuickStart/static/backstageSystemModel.png b/plugins/home/src/homePageComponents/QuickStart/static/backstageSystemModel.png new file mode 100644 index 0000000000..ad784060bb Binary files /dev/null and b/plugins/home/src/homePageComponents/QuickStart/static/backstageSystemModel.png differ diff --git a/plugins/home/src/homePageComponents/QuickStart/styles.ts b/plugins/home/src/homePageComponents/QuickStart/styles.ts new file mode 100644 index 0000000000..f6f93f7070 --- /dev/null +++ b/plugins/home/src/homePageComponents/QuickStart/styles.ts @@ -0,0 +1,68 @@ +/* + * Copyright 2022 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 { makeStyles, Theme } from '@material-ui/core/styles'; + +/** @public */ +export type QuickStartCardClassKey = + | 'cardTitleIcon' + | 'contentActionContainer' + | 'contentModal' + | 'imageSize' + | 'link' + | 'linkText' + | 'videoContainer'; + +export const useStyles = makeStyles( + (theme: Theme) => ({ + cardTitleIcon: { + verticalAlign: 'bottom', + marginLeft: '-4px', + }, + contentActionContainer: { + marginTop: theme.spacing(1.5), + marginBottom: theme.spacing(1.5), + }, + contentModal: { + position: 'absolute', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: '80%', + height: 'auto', + }, + imageSize: { width: '100%', height: '100%' }, + link: { + display: 'inline-flex', + alignItems: 'center', + textDecoration: 'none', + color: `${theme.palette.link}`, + '&:hover': { + background: 'transparent', + }, + }, + linkText: { + marginBottom: theme.spacing(1.5), + }, + videoContainer: { + borderRadius: '10px', + width: '100%', + height: 'auto', + background: `${theme.palette.background.default}`, + }, + }), + { name: 'HomeQuickStartCard' }, +); diff --git a/plugins/home/src/homePageComponents/index.ts b/plugins/home/src/homePageComponents/index.ts index e260982e8e..f2eb39b070 100644 --- a/plugins/home/src/homePageComponents/index.ts +++ b/plugins/home/src/homePageComponents/index.ts @@ -20,3 +20,4 @@ export type { WelcomeTitleLanguageProps } from './WelcomeTitle'; export type { VisitedByTypeProps, VisitedByTypeKind } from './VisitedByType'; export type { FeaturedDocsCardProps } from './FeaturedDocsCard'; export type { StarredEntitiesProps } from './StarredEntities'; +export type { QuickStartCardProps } from './QuickStart'; diff --git a/plugins/home/src/plugin.ts b/plugins/home/src/plugin.ts index c3fa938197..6892db2231 100644 --- a/plugins/home/src/plugin.ts +++ b/plugins/home/src/plugin.ts @@ -27,6 +27,7 @@ import { ToolkitContentProps, VisitedByTypeProps, FeaturedDocsCardProps, + QuickStartCardProps, } from './homePageComponents'; import { rootRouteRef } from './routes'; import { VisitsStorageApi, visitsApiRef } from './api'; @@ -230,3 +231,16 @@ export const FeaturedDocsCard = homePlugin.provide( components: () => import('./homePageComponents/FeaturedDocsCard'), }), ); + +/** + * A component to display Quick Start information. + * + * @public + */ +export const QuickStartCard = homePlugin.provide( + createCardExtension({ + name: 'QuickStartCard', + title: 'Quick Start', + components: () => import('./homePageComponents/QuickStart'), + }), +); diff --git a/plugins/kubernetes-backend/CHANGELOG.md b/plugins/kubernetes-backend/CHANGELOG.md index 2539af73fd..37d7d9dedb 100644 --- a/plugins/kubernetes-backend/CHANGELOG.md +++ b/plugins/kubernetes-backend/CHANGELOG.md @@ -1,5 +1,87 @@ # @backstage/plugin-kubernetes-backend +## 0.19.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-kubernetes-node@0.2.1-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.19.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-kubernetes-node@0.2.1-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-permission-common@0.8.2 + +## 0.19.1-next.0 + +### Patch Changes + +- cbfc69e: Create a `dev/index.ts` entrypoint for `yarn start` +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-node@0.2.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 0.19.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- bee9664: Adapted the config.d.ts for custom k8s cluster authProvider implementations +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-node@0.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + ## 0.19.0-next.3 ### Patch Changes diff --git a/plugins/kubernetes-backend/dev/index.ts b/plugins/kubernetes-backend/dev/index.ts new file mode 100644 index 0000000000..dc287d46cc --- /dev/null +++ b/plugins/kubernetes-backend/dev/index.ts @@ -0,0 +1,21 @@ +/* + * 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 { createBackend } from '@backstage/backend-defaults'; + +const backend = createBackend(); +backend.add(import('../src')); +backend.start(); diff --git a/plugins/kubernetes-backend/package.json b/plugins/kubernetes-backend/package.json index 35be07ad5c..7f55f24417 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.0-next.3", + "version": "0.19.1-next.2", "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 5264e762b6..01da602232 100644 --- a/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts +++ b/plugins/kubernetes-backend/src/routes/resourceRoutes.test.ts @@ -108,7 +108,7 @@ describe('resourcesRoutes', () => { }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'test-objects-provider', diff --git a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts index 3299d11e5d..b38bf9121a 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesBuilder.test.ts @@ -121,8 +121,8 @@ describe('API integration tests', () => { const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), - import('@backstage/plugin-permission-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), + import('@backstage/plugin-permission-backend'), import('@backstage/plugin-permission-backend-module-allow-all-policy'), createBackendModule({ pluginId: 'kubernetes', @@ -187,7 +187,7 @@ describe('API integration tests', () => { const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testObjectsProvider', @@ -284,7 +284,7 @@ describe('API integration tests', () => { const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), withClusters([ { name: 'cluster-name', @@ -377,7 +377,7 @@ describe('API integration tests', () => { const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), withClusters(clusters), createBackendModule({ pluginId: 'kubernetes', @@ -440,7 +440,7 @@ describe('API integration tests', () => { const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), withClusters([ { name: 'custom-cluster', @@ -579,7 +579,7 @@ metadata: features: [ minimalValidConfigService, permissionsMock.factory, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), ], }); app = server; @@ -614,7 +614,7 @@ metadata: const { server } = await startTestBackend({ features: [ minimalValidConfigService, - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), withClusters([ { name: 'custom-cluster', @@ -689,7 +689,7 @@ metadata: }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -741,7 +741,7 @@ metadata: }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testAuthStrategy', @@ -796,7 +796,7 @@ metadata: }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), ], }), ).rejects.toThrow( diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts index 3491268d39..ac6a59a7c4 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.test.ts @@ -31,6 +31,7 @@ import { registerMswTestHooks, } from '@backstage/backend-test-utils'; import { + CustomResourceFetchResponse, FetchResponse, KubernetesRequestAuth, ObjectsByEntityResponse, @@ -1428,5 +1429,78 @@ describe('KubernetesFanOutHandler', () => { }), ); }); + it('fetch pod metrics when pods used', async () => { + getClustersByEntity.mockImplementation(() => + Promise.resolve({ + clusters: [ + { + name: 'test-cluster', + title: 'cluster-title', + url: '', + authMetadata: {}, + }, + ], + }), + ); + + sut = getKubernetesFanOutHandler([]); + + const resources: CustomResourceFetchResponse[] = [ + { + type: 'customresources', + resources: [ + { + apiVersion: 'v1', + kind: 'Pod', + metadata: { + namespace: `ns-test-component-test-cluster`, + }, + }, + ], + }, + ]; + + fetchObjectsForService.mockImplementation(async () => ({ + responses: resources, + errors: [], + })); + + const result = await sut.getCustomResourcesByEntity( + { + entity, + auth: {}, + customResources: [ + { + group: '', + apiVersion: 'v1', + plural: 'pods', + }, + ], + }, + { credentials: mockCredentials }, + ); + + expect(fetchObjectsForService).toHaveBeenCalledTimes(1); + expect(fetchPodMetricsByNamespaces).toHaveBeenCalledTimes(1); + expect(fetchPodMetricsByNamespaces).toHaveBeenCalledWith( + expect.anything(), + { type: 'anonymous' }, + new Set(['ns-test-component-test-cluster']), + expect.anything(), + ); + expect(result).toStrictEqual({ + items: [ + { + cluster: { + name: 'test-cluster', + title: 'cluster-title', + }, + errors: [], + podMetrics: [POD_METRICS_FIXTURE], + resources, + }, + ], + }); + }); }); }); diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 54a038fffd..31c0c91807 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -147,7 +147,11 @@ export interface KubernetesFanOutHandlerOptions export interface KubernetesRequestBody extends ObjectsByEntityRequest {} const isPodFetchResponse = (fr: FetchResponse): fr is PodFetchResponse => - fr.type === 'pods'; + fr.type === 'pods' || + (fr.type === 'customresources' && + fr.resources.length > 0 && + fr.resources[0].apiVersion === 'v1' && + fr.resources[0].kind === 'Pod'); const isString = (str: string | undefined): str is string => str !== undefined; const numberOrBigIntToNumberOrString = ( diff --git a/plugins/kubernetes-backend/src/service/standaloneApplication.ts b/plugins/kubernetes-backend/src/service/standaloneApplication.ts deleted file mode 100644 index dd87d33827..0000000000 --- a/plugins/kubernetes-backend/src/service/standaloneApplication.ts +++ /dev/null @@ -1,68 +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 { - errorHandler, - notFoundHandler, - requestLoggingHandler, - HostDiscovery, -} from '@backstage/backend-common'; -import compression from 'compression'; -import cors from 'cors'; -import express from 'express'; -import helmet from 'helmet'; -import { Logger } from 'winston'; -import { createRouter } from './router'; -import { ConfigReader } from '@backstage/config'; -import { CatalogClient } from '@backstage/catalog-client'; -import { PermissionEvaluator } from '@backstage/plugin-permission-common'; - -export interface ApplicationOptions { - enableCors: boolean; - logger: Logger; -} - -export async function createStandaloneApplication( - options: ApplicationOptions, -): Promise { - const { enableCors, logger } = options; - const config = new ConfigReader({}); - const discovery = HostDiscovery.fromConfig(config); - - const app = express(); - - const catalogApi = new CatalogClient({ - discoveryApi: HostDiscovery.fromConfig(config), - }); - - const permissions = {} as PermissionEvaluator; - - app.use(helmet()); - if (enableCors) { - app.use(cors()); - } - app.use(compression()); - app.use(express.json()); - app.use(requestLoggingHandler()); - app.use( - '/', - await createRouter({ logger, config, discovery, catalogApi, permissions }), - ); - app.use(notFoundHandler()); - app.use(errorHandler()); - - return app; -} diff --git a/plugins/kubernetes-backend/src/service/standaloneServer.ts b/plugins/kubernetes-backend/src/service/standaloneServer.ts deleted file mode 100644 index 9f9217fd4c..0000000000 --- a/plugins/kubernetes-backend/src/service/standaloneServer.ts +++ /dev/null @@ -1,50 +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 { Server } from 'http'; -import { Logger } from 'winston'; -import { createStandaloneApplication } from './standaloneApplication'; - -export interface ServerOptions { - port: number; - enableCors: boolean; - logger: Logger; -} - -export async function startStandaloneServer( - options: ServerOptions, -): Promise { - const logger = options.logger.child({ service: 'kubernetes-backend' }); - - logger.debug('Creating application...'); - const app = await createStandaloneApplication({ - enableCors: options.enableCors, - logger, - }); - - logger.debug('Starting application server...'); - return await new Promise((resolve, reject) => { - const server = app.listen(options.port, (err?: Error) => { - if (err) { - reject(err); - return; - } - - logger.info(`Listening on port ${options.port}`); - resolve(server); - }); - }); -} diff --git a/plugins/kubernetes-cluster/CHANGELOG.md b/plugins/kubernetes-cluster/CHANGELOG.md index de52996ef8..359515568b 100644 --- a/plugins/kubernetes-cluster/CHANGELOG.md +++ b/plugins/kubernetes-cluster/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-kubernetes-cluster +## 0.0.20-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.2 + +## 0.0.20-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.1 + +## 0.0.20-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.0 + +## 0.0.18 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + ## 0.0.18-next.3 ### Patch Changes diff --git a/plugins/kubernetes-cluster/package.json b/plugins/kubernetes-cluster/package.json index 25c990032d..29f1e857f5 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.18-next.3", + "version": "0.0.20-next.2", "description": "A Backstage plugin that shows details of Kubernetes clusters", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes-common/CHANGELOG.md b/plugins/kubernetes-common/CHANGELOG.md index 76eb3e4ed2..3b594da93a 100644 --- a/plugins/kubernetes-common/CHANGELOG.md +++ b/plugins/kubernetes-common/CHANGELOG.md @@ -1,5 +1,27 @@ # @backstage/plugin-kubernetes-common +## 0.9.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.9.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + ## 0.9.0-next.0 ### Minor Changes diff --git a/plugins/kubernetes-common/package.json b/plugins/kubernetes-common/package.json index 6310e5f6b9..0f01a38dd4 100644 --- a/plugins/kubernetes-common/package.json +++ b/plugins/kubernetes-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-common", - "version": "0.9.0-next.0", + "version": "0.9.1-next.0", "description": "Common functionalities for kubernetes, to be shared between kubernetes and kubernetes-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/kubernetes-node/CHANGELOG.md b/plugins/kubernetes-node/CHANGELOG.md index ef324f5079..d4d69efd81 100644 --- a/plugins/kubernetes-node/CHANGELOG.md +++ b/plugins/kubernetes-node/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-kubernetes-node +## 0.2.1-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## 0.2.1-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.2.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.2.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + ## 0.2.0-next.2 ### Patch Changes diff --git a/plugins/kubernetes-node/package.json b/plugins/kubernetes-node/package.json index a07d42b9c1..b15d289766 100644 --- a/plugins/kubernetes-node/package.json +++ b/plugins/kubernetes-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes-node", - "version": "0.2.0-next.2", + "version": "0.2.1-next.2", "description": "Node.js library for the kubernetes plugin", "backstage": { "role": "node-library", diff --git a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts index 65e48affc0..524e034117 100644 --- a/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts +++ b/plugins/kubernetes-node/src/auth/PinnipedHelper.test.ts @@ -90,7 +90,7 @@ describe('Pinniped - tokenCredentialRequest', () => { }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testClusterSupplier', @@ -261,7 +261,7 @@ describe('Pinniped - tokenCredentialRequest', () => { }, }, }), - import('@backstage/plugin-kubernetes-backend/alpha'), + import('@backstage/plugin-kubernetes-backend'), createBackendModule({ pluginId: 'kubernetes', moduleId: 'testClusterSupplier', diff --git a/plugins/kubernetes-react/CHANGELOG.md b/plugins/kubernetes-react/CHANGELOG.md index da8c075e66..902d065b8b 100644 --- a/plugins/kubernetes-react/CHANGELOG.md +++ b/plugins/kubernetes-react/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-kubernetes-react +## 0.5.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + +## 0.5.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.5.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-kubernetes-common@0.9.0 + +## 0.5.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- 0b729da: add the pod delete feature to the kubernetes react plugin +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + ## 0.5.0-next.2 ### Patch Changes diff --git a/plugins/kubernetes-react/package.json b/plugins/kubernetes-react/package.json index 30d76d459c..f84cc7d881 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.0-next.2", + "version": "0.5.2-next.2", "description": "Web library for the kubernetes-react plugin", "backstage": { "role": "web-library", diff --git a/plugins/kubernetes/CHANGELOG.md b/plugins/kubernetes/CHANGELOG.md index 6593d66a3d..760c72b323 100644 --- a/plugins/kubernetes/CHANGELOG.md +++ b/plugins/kubernetes/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-kubernetes +## 0.12.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-kubernetes-common@0.9.1-next.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.2 + +## 0.12.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.1 + +## 0.12.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/plugin-kubernetes-react@0.5.2-next.0 + +## 0.12.0 + +### Minor Changes + +- 71b8704: Bumping @kubernetes/client-node to 1.0.0-rc7 to mitigate CVEs related to the request and tough-cookie packages + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-kubernetes-react@0.5.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-kubernetes-common@0.9.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + ## 0.12.0-next.3 ### Patch Changes diff --git a/plugins/kubernetes/package.json b/plugins/kubernetes/package.json index 783590ccdc..b13743f3bf 100644 --- a/plugins/kubernetes/package.json +++ b/plugins/kubernetes/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-kubernetes", - "version": "0.12.0-next.3", + "version": "0.12.2-next.2", "description": "A Backstage plugin that integrates towards Kubernetes", "backstage": { "role": "frontend-plugin", diff --git a/plugins/kubernetes/report-alpha.api.md b/plugins/kubernetes/report-alpha.api.md index 9ba748577f..4f779df258 100644 --- a/plugins/kubernetes/report-alpha.api.md +++ b/plugins/kubernetes/report-alpha.api.md @@ -21,21 +21,6 @@ const _default: FrontendPlugin< }, {}, { - 'api:kubernetes': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'page:kubernetes': ExtensionDefinition<{ kind: 'page'; name: undefined; @@ -62,6 +47,21 @@ const _default: FrontendPlugin< routeRef?: RouteRef | undefined; }; }>; + 'api:kubernetes': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; 'entity-content:kubernetes/kubernetes': ExtensionDefinition<{ kind: 'entity-content'; name: 'kubernetes'; diff --git a/plugins/notifications-backend-module-email/CHANGELOG.md b/plugins/notifications-backend-module-email/CHANGELOG.md index 1cf82511dc..0fc9419cfc 100644 --- a/plugins/notifications-backend-module-email/CHANGELOG.md +++ b/plugins/notifications-backend-module-email/CHANGELOG.md @@ -1,5 +1,67 @@ # @backstage/plugin-notifications-backend-module-email +## 0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## 0.3.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + +## 0.3.3 + +### Patch Changes + +- d52d7f9: Support ISO and ms string forms of durations in config too +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/catalog-model@1.7.1 + ## 0.3.3-next.3 ### Patch Changes diff --git a/plugins/notifications-backend-module-email/config.d.ts b/plugins/notifications-backend-module-email/config.d.ts index 04e6f7910f..eaed835485 100644 --- a/plugins/notifications-backend-module-email/config.d.ts +++ b/plugins/notifications-backend-module-email/config.d.ts @@ -99,7 +99,7 @@ export interface Config { /** * Throttle duration between email sending, defaults to 100ms */ - throttleInterval?: HumanDuration; + throttleInterval?: HumanDuration | string; /** * Configuration for broadcast notifications */ @@ -120,7 +120,7 @@ export interface Config { /** * Email cache TTL, defaults to 1 hour */ - ttl?: HumanDuration; + ttl?: HumanDuration | string; }; filter?: { /** diff --git a/plugins/notifications-backend-module-email/package.json b/plugins/notifications-backend-module-email/package.json index 4b2eb3a5b6..f86214a7c0 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.3-next.3", + "version": "0.3.4-next.2", "description": "The email backend module for the notifications plugin.", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts index 9337915ecc..c88dda2ac0 100644 --- a/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts +++ b/plugins/notifications-backend-module-email/src/processor/NotificationsEmailProcessor.ts @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { NotificationProcessor, NotificationSendOptions, @@ -75,14 +76,17 @@ export class NotificationsEmailProcessor implements NotificationProcessor { this.replyTo = emailProcessorConfig.getOptionalString('replyTo'); this.concurrencyLimit = emailProcessorConfig.getOptionalNumber('concurrencyLimit') ?? 2; - const throttleConfig = - emailProcessorConfig.getOptionalConfig('throttleInterval'); - this.throttleInterval = throttleConfig - ? durationToMilliseconds(readDurationFromConfig(throttleConfig)) + this.throttleInterval = emailProcessorConfig.has('throttleInterval') + ? durationToMilliseconds( + readDurationFromConfig(emailProcessorConfig, { + key: 'throttleInterval', + }), + ) : 100; - const cacheConfig = emailProcessorConfig.getOptionalConfig('cache.ttl'); - this.cacheTtl = cacheConfig - ? durationToMilliseconds(readDurationFromConfig(cacheConfig)) + this.cacheTtl = emailProcessorConfig.has('cache.ttl') + ? durationToMilliseconds( + readDurationFromConfig(emailProcessorConfig, { key: 'cache.ttl' }), + ) : 3_600_000; this.frontendBaseUrl = config.getString('app.baseUrl'); this.allowlistEmailAddresses = emailProcessorConfig.getOptionalStringArray( diff --git a/plugins/notifications-backend/CHANGELOG.md b/plugins/notifications-backend/CHANGELOG.md index 940fb90b0a..f8aab11db2 100644 --- a/plugins/notifications-backend/CHANGELOG.md +++ b/plugins/notifications-backend/CHANGELOG.md @@ -1,5 +1,81 @@ # @backstage/plugin-notifications-backend +## 0.5.0-next.2 + +### Minor Changes + +- fc15b77: **BREAKING**: Removed redundant `/health` endpoint, switch to using [the built-in endpoint instead](https://backstage.io/docs/backend-system/core-services/root-health). + +### Patch Changes + +- fc15b77: Deprecated root '/' endpoints, moving them under `/notifications` instead. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## 0.4.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-notifications-common@0.0.6 + +## 0.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + +## 0.4.3 + +### Patch Changes + +- 97ba58f: Add support for user specific notification settings +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-events-node@0.4.5 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + ## 0.4.3-next.3 ### Patch Changes diff --git a/plugins/notifications-backend/README.md b/plugins/notifications-backend/README.md index a6b6615d9f..080f1e746b 100644 --- a/plugins/notifications-backend/README.md +++ b/plugins/notifications-backend/README.md @@ -29,5 +29,5 @@ To be able to do so, `external access` needs to be enabled as described in the [ Once the API can be accessed, the request can look like: ``` -curl -X POST [YOUR_SERVER_URL]/api/notifications -H "Content-Type: application/json" -H "Authorization: Bearer [BASE64_ENCODED_ACCESS_TOKEN]" -d '{"recipients":{"type":"entity","entityRef":"user:development/guest"},"payload": {"title": "Title of user-targeted external message","description": "The description","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}' +curl -X POST [YOUR_SERVER_URL]/api/notifications/notifications -H "Content-Type: application/json" -H "Authorization: Bearer [BASE64_ENCODED_ACCESS_TOKEN]" -d '{"recipients":{"type":"entity","entityRef":"user:development/guest"},"payload": {"title": "Title of user-targeted external message","description": "The description","link": "http://foo.com/bar","severity": "high","topic": "The topic"}}' ``` diff --git a/plugins/notifications-backend/dev/index.ts b/plugins/notifications-backend/dev/index.ts index 5ee822c0cf..cee630d1ad 100644 --- a/plugins/notifications-backend/dev/index.ts +++ b/plugins/notifications-backend/dev/index.ts @@ -109,7 +109,7 @@ const notificationsDebug = createBackendPlugin({ }); const backend = createBackend(); -backend.add(import('@backstage/plugin-events-backend/alpha')); +backend.add(import('@backstage/plugin-events-backend')); backend.add(import('@backstage/plugin-signals-backend')); backend.add(import('@backstage/plugin-auth-backend')); backend.add(import('@backstage/plugin-auth-backend-module-guest-provider')); diff --git a/plugins/notifications-backend/package.json b/plugins/notifications-backend/package.json index 0d08966b83..a1ba6a8b54 100644 --- a/plugins/notifications-backend/package.json +++ b/plugins/notifications-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications-backend", - "version": "0.4.3-next.3", + "version": "0.5.0-next.2", "backstage": { "role": "backend-plugin", "pluginId": "notifications", @@ -53,7 +53,6 @@ "express": "^4.17.1", "express-promise-router": "^4.1.0", "knex": "^3.0.0", - "node-fetch": "^2.7.0", "uuid": "^11.0.0", "winston": "^3.2.1", "yn": "^4.0.0" diff --git a/plugins/notifications-backend/src/service/router.test.ts b/plugins/notifications-backend/src/service/router.test.ts index 470532b2dc..5126181c4f 100644 --- a/plugins/notifications-backend/src/service/router.test.ts +++ b/plugins/notifications-backend/src/service/router.test.ts @@ -23,7 +23,11 @@ import request from 'supertest'; import { createRouter } from './router'; import { ConfigReader } from '@backstage/config'; import { SignalsService } from '@backstage/plugin-signals-node'; -import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; +import { + mockCredentials, + mockErrorHandler, + mockServices, +} from '@backstage/backend-test-utils'; import { NotificationSendOptions } from '@backstage/plugin-notifications-node'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; @@ -68,26 +72,17 @@ describe('createRouter', () => { auth, catalog, }); - app = express().use(router); + app = express().use(router).use(mockErrorHandler()); }); beforeEach(() => { jest.resetAllMocks(); }); - describe('GET /health', () => { - it('returns ok', async () => { - const response = await request(app).get('/health'); - - expect(response.status).toEqual(200); - expect(response.body).toEqual({ status: 'ok' }); - }); - }); - - describe('POST /', () => { + describe('POST /notifications', () => { const sendNotification = async (data: NotificationSendOptions) => request(app) - .post('/') + .post('/notifications') .send(data) .set('Content-Type', 'application/json') .set('Accept', 'application/json'); diff --git a/plugins/notifications-backend/src/service/router.ts b/plugins/notifications-backend/src/service/router.ts index 88cd1fd337..8a12a53be5 100644 --- a/plugins/notifications-backend/src/service/router.ts +++ b/plugins/notifications-backend/src/service/router.ts @@ -14,8 +14,7 @@ * limitations under the License. */ -import { errorHandler, PluginDatabaseManager } from '@backstage/backend-common'; -import express, { Request } from 'express'; +import express, { Request, Response } from 'express'; import Router from 'express-promise-router'; import { DatabaseNotificationsStore, @@ -31,6 +30,7 @@ import { import { InputError, NotFoundError } from '@backstage/errors'; import { AuthService, + DatabaseService, HttpAuthService, LoggerService, UserInfoService, @@ -53,7 +53,7 @@ import { Config } from '@backstage/config'; export interface RouterOptions { logger: LoggerService; config: Config; - database: PluginDatabaseManager; + database: DatabaseService; auth: AuthService; httpAuth: HttpAuthService; userInfo: UserInfoService; @@ -250,12 +250,7 @@ export async function createRouter( const router = Router(); router.use(express.json()); - router.get('/health', (_, response) => { - logger.info('PONG!'); - response.json({ status: 'ok' }); - }); - - router.get('/', async (req, res) => { + const listNotificationsHandler = async (req: Request, res: Response) => { const user = await getUser(req); const opts: NotificationGetOptions = { user: user, @@ -310,7 +305,10 @@ export async function createRouter( totalCount, notifications, }); - }); + }; + + router.get('/', listNotificationsHandler); // Deprecated endpoint + router.get('/notifications', listNotificationsHandler); router.get('/status', async (req: Request, res) => { const user = await getUser(req); @@ -345,8 +343,7 @@ export async function createRouter( }, ); - // Make sure this is the last "GET" handler - router.get('/:id', async (req, res) => { + const getNotificationHandler = async (req: Request, res: Response) => { const user = await getUser(req); const opts: NotificationGetOptions = { user: user, @@ -358,9 +355,13 @@ export async function createRouter( throw new NotFoundError('Not found'); } res.json(notifications[0]); - }); + }; - router.post('/update', async (req, res) => { + // Make sure this is the last "GET" handler + router.get('/:id', getNotificationHandler); // Deprecated endpoint + router.get('/notifications/:id', getNotificationHandler); + + const updateNotificationsHandler = async (req: Request, res: Response) => { const user = await getUser(req); const { ids, read, saved } = req.body; if (!ids || !Array.isArray(ids)) { @@ -397,7 +398,10 @@ export async function createRouter( const notifications = await store.getNotifications({ ids, user: user }); res.json(notifications); - }); + }; + + router.post('/update', updateNotificationsHandler); // Deprecated endpoint + router.post('/notifications/update', updateNotificationsHandler); const sendBroadcastNotification = async ( baseNotification: Omit, @@ -509,77 +513,79 @@ export async function createRouter( return notifications; }; - // Add new notification - router.post( - '/', - async (req: Request, res) => { - const credentials = await httpAuth.credentials(req, { - allow: ['service'], - }); + const createNotificationHandler = async ( + req: Request, + res: Response, + ) => { + const credentials = await httpAuth.credentials(req, { + allow: ['service'], + }); - const origin = credentials.principal.subject; - const opts = await processOptions(req.body, origin); - const { recipients, payload } = opts; - const { title, link } = payload; - const notifications: Notification[] = []; - let users = []; + const origin = credentials.principal.subject; + const opts = await processOptions(req.body, origin); + const { recipients, payload } = opts; + const { title, link } = payload; + const notifications: Notification[] = []; + let users = []; - if (!recipients || !title) { - logger.error(`Invalid notification request received`); - throw new InputError(`Invalid notification request received`); + if (!recipients || !title) { + logger.error(`Invalid notification request received`); + throw new InputError(`Invalid notification request received`); + } + + if (link) { + try { + validateLink(link); + } catch (e) { + throw new InputError('Invalid link provided', e); } + } - if (link) { - try { - validateLink(link); - } catch (e) { - throw new InputError('Invalid link provided', e); - } - } + const baseNotification = { + payload: { + ...payload, + severity: payload.severity ?? 'normal', + }, + origin, + created: new Date(), + }; - const baseNotification = { - payload: { - ...payload, - severity: payload.severity ?? 'normal', - }, + if (recipients.type === 'broadcast') { + const broadcast = await sendBroadcastNotification( + baseNotification, + opts, origin, - created: new Date(), - }; + ); + notifications.push(broadcast); + } else { + const entityRef = recipients.entityRef; - if (recipients.type === 'broadcast') { - const broadcast = await sendBroadcastNotification( - baseNotification, - opts, - origin, + try { + users = await getUsersForEntityRef( + entityRef, + recipients.excludeEntityRef ?? [], + { auth, catalogClient: catalog }, ); - notifications.push(broadcast); - } else { - const entityRef = recipients.entityRef; - - try { - users = await getUsersForEntityRef( - entityRef, - recipients.excludeEntityRef ?? [], - { auth, catalogClient: catalog }, - ); - } catch (e) { - logger.error(`Failed to resolve notification receivers: ${e}`); - throw new InputError('Failed to resolve notification receivers', e); - } - - const userNotifications = await sendUserNotifications( - baseNotification, - users, - opts, - origin, - ); - notifications.push(...userNotifications); + } catch (e) { + logger.error(`Failed to resolve notification receivers: ${e}`); + throw new InputError('Failed to resolve notification receivers', e); } - res.json(notifications); - }, - ); + const userNotifications = await sendUserNotifications( + baseNotification, + users, + opts, + origin, + ); + notifications.push(...userNotifications); + } + + res.json(notifications); + }; + + // Add new notification + router.post('/', createNotificationHandler); + router.post('/notifications', createNotificationHandler); - router.use(errorHandler()); return router; } diff --git a/plugins/notifications-common/CHANGELOG.md b/plugins/notifications-common/CHANGELOG.md index e01a76c0d7..8b536cc17f 100644 --- a/plugins/notifications-common/CHANGELOG.md +++ b/plugins/notifications-common/CHANGELOG.md @@ -1,5 +1,20 @@ # @backstage/plugin-notifications-common +## 0.0.7-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + +## 0.0.6 + +### Patch Changes + +- 97ba58f: Add support for user specific notification settings +- Updated dependencies + - @backstage/config@1.3.0 + ## 0.0.6-next.0 ### Patch Changes diff --git a/plugins/notifications-common/package.json b/plugins/notifications-common/package.json index 4b8ddec289..7d5689fb77 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.6-next.0", + "version": "0.0.7-next.0", "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 ae909882db..d35c6a9c9a 100644 --- a/plugins/notifications-node/CHANGELOG.md +++ b/plugins/notifications-node/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-notifications-node +## 0.2.10-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## 0.2.10-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-notifications-common@0.0.6 + +## 0.2.10-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-node@0.1.15-next.0 + +## 0.2.9 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/catalog-model@1.7.1 + ## 0.2.9-next.3 ### Patch Changes diff --git a/plugins/notifications-node/package.json b/plugins/notifications-node/package.json index b7718f55c6..56db67f3cf 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.9-next.3", + "version": "0.2.10-next.2", "description": "Node.js library for the notifications plugin", "backstage": { "role": "node-library", @@ -43,7 +43,6 @@ "@backstage/plugin-notifications-common": "workspace:^", "@backstage/plugin-signals-node": "workspace:^", "knex": "^3.0.0", - "node-fetch": "^2.7.0", "uuid": "^11.0.0" }, "devDependencies": { diff --git a/plugins/notifications-node/src/service/DefaultNotificationService.ts b/plugins/notifications-node/src/service/DefaultNotificationService.ts index 7a46e01689..8ea58f22d3 100644 --- a/plugins/notifications-node/src/service/DefaultNotificationService.ts +++ b/plugins/notifications-node/src/service/DefaultNotificationService.ts @@ -17,7 +17,6 @@ import { NotificationService } from './NotificationService'; import { AuthService, DiscoveryService } from '@backstage/backend-plugin-api'; import { NotificationPayload } from '@backstage/plugin-notifications-common'; -import fetch from 'node-fetch'; /** @public */ export type NotificationServiceOptions = { diff --git a/plugins/notifications/CHANGELOG.md b/plugins/notifications/CHANGELOG.md index 311117b79c..06ce8f8206 100644 --- a/plugins/notifications/CHANGELOG.md +++ b/plugins/notifications/CHANGELOG.md @@ -1,5 +1,70 @@ # @backstage/plugin-notifications +## 0.5.0-next.2 + +### Minor Changes + +- fc15b77: Switched to using the new `/notifications` endpoints. Be sure to update the `notifications` plugin backend before deploying this frontend plugin change. + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.7-next.0 + - @backstage/plugin-signals-react@0.0.8-next.0 + +## 0.4.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-react@0.0.7 + +## 0.4.2-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-signals-react@0.0.7 + +## 0.4.0 + +### Minor Changes + +- 87ffc1c: Rephrasing labels of the View filter to be more clear. Based on the received users' feedback. + +### Patch Changes + +- 4186105: Added title to the Notifications' table. The title clearly states the filter selection and total count of messages. This change aligns the look and feel closer to other tables. +- 3a0731e: The "Created after" filter renamed to the "Sent out" based on the received users' feedback. +- 3e135f2: The notification's title is emphasized to be clearly distinguished from the description. +- 97ba58f: Add support for user specific notification settings +- 1d87c43: Show count of unread notifications in the left-side MenuItem. This replaces the simple true/false bullet. +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-signals-react@0.0.7 + ## 0.3.3-next.2 ### Patch Changes diff --git a/plugins/notifications/package.json b/plugins/notifications/package.json index 8c3dde897d..a2ca6a3f20 100644 --- a/plugins/notifications/package.json +++ b/plugins/notifications/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-notifications", - "version": "0.3.3-next.2", + "version": "0.5.0-next.2", "backstage": { "role": "frontend-plugin", "pluginId": "notifications", diff --git a/plugins/notifications/src/api/NotificationsClient.test.ts b/plugins/notifications/src/api/NotificationsClient.test.ts index f378269e45..8248ea9331 100644 --- a/plugins/notifications/src/api/NotificationsClient.test.ts +++ b/plugins/notifications/src/api/NotificationsClient.test.ts @@ -48,7 +48,7 @@ describe('NotificationsClient', () => { it('should fetch notifications from correct endpoint', async () => { server.use( - rest.get(`${mockBaseUrl}/`, (_, res, ctx) => + rest.get(`${mockBaseUrl}/notifications`, (_, res, ctx) => res(ctx.json(expectedResp)), ), ); @@ -58,7 +58,7 @@ describe('NotificationsClient', () => { it('should fetch notifications with options', async () => { server.use( - rest.get(`${mockBaseUrl}/`, (req, res, ctx) => { + rest.get(`${mockBaseUrl}/notifications`, (req, res, ctx) => { expect(req.url.search).toBe( '?limit=10&offset=0&search=find+me&read=true&createdAfter=1970-01-01T00%3A00%3A00.005Z', ); @@ -77,7 +77,7 @@ describe('NotificationsClient', () => { it('should omit unselected fetch options', async () => { server.use( - rest.get(`${mockBaseUrl}/`, (req, res, ctx) => { + rest.get(`${mockBaseUrl}/notifications`, (req, res, ctx) => { expect(req.url.search).toBe('?limit=10'); return res(ctx.json(expectedResp)); }), @@ -91,7 +91,7 @@ describe('NotificationsClient', () => { it('should fetch single notification', async () => { server.use( - rest.get(`${mockBaseUrl}/:id`, (req, res, ctx) => { + rest.get(`${mockBaseUrl}/notifications/:id`, (req, res, ctx) => { expect(req.params.id).toBe('acdaa8ca-262b-43c1-b74b-de06e5f3b3c7'); return res(ctx.json(testNotification)); }), @@ -115,12 +115,15 @@ describe('NotificationsClient', () => { it('should update notifications', async () => { server.use( - rest.post(`${mockBaseUrl}/update`, async (req, res, ctx) => { - expect(await req.json()).toEqual({ - ids: ['acdaa8ca-262b-43c1-b74b-de06e5f3b3c7'], - }); - return res(ctx.json(expectedResp)); - }), + rest.post( + `${mockBaseUrl}/notifications/update`, + async (req, res, ctx) => { + expect(await req.json()).toEqual({ + ids: ['acdaa8ca-262b-43c1-b74b-de06e5f3b3c7'], + }); + return res(ctx.json(expectedResp)); + }, + ), ); const response = await client.updateNotifications({ ids: ['acdaa8ca-262b-43c1-b74b-de06e5f3b3c7'], diff --git a/plugins/notifications/src/api/NotificationsClient.ts b/plugins/notifications/src/api/NotificationsClient.ts index 983065f96e..5e763ecb8c 100644 --- a/plugins/notifications/src/api/NotificationsClient.ts +++ b/plugins/notifications/src/api/NotificationsClient.ts @@ -71,23 +71,26 @@ export class NotificationsClient implements NotificationsApi { if (options?.minimumSeverity !== undefined) { queryString.append('minimumSeverity', options.minimumSeverity); } - const urlSegment = `?${queryString}`; - return await this.request(urlSegment); + return await this.request( + `/notifications?${queryString}`, + ); } async getNotification(id: string): Promise { - return await this.request(`${id}`); + return await this.request( + `/notifications/${encodeURIComponent(id)}`, + ); } async getStatus(): Promise { - return await this.request('status'); + return await this.request('/status'); } async updateNotifications( options: UpdateNotificationsOptions, ): Promise { - return await this.request('update', { + return await this.request('/notifications/update', { method: 'POST', body: JSON.stringify(options), headers: { 'Content-Type': 'application/json' }, @@ -95,29 +98,27 @@ export class NotificationsClient implements NotificationsApi { } async getNotificationSettings(): Promise { - return await this.request('settings'); + return await this.request('/settings'); } async updateNotificationSettings( settings: NotificationSettings, ): Promise { - return await this.request('settings', { + return await this.request('/settings', { method: 'POST', body: JSON.stringify(settings), headers: { 'Content-Type': 'application/json' }, }); } - private async request(path: string, init?: any): Promise { - const baseUrl = `${await this.discoveryApi.getBaseUrl('notifications')}/`; - const url = new URL(path, baseUrl); + private async request(path: string, init?: RequestInit): Promise { + const baseUrl = await this.discoveryApi.getBaseUrl('notifications'); + const res = await this.fetchApi.fetch(`${baseUrl}${path}`, init); - const response = await this.fetchApi.fetch(url.toString(), init); - - if (!response.ok) { - throw await ResponseError.fromResponse(response); + if (!res.ok) { + throw await ResponseError.fromResponse(res); } - return response.json() as Promise; + return res.json() as Promise; } } diff --git a/plugins/notifications/src/components/NotificationsFilters/NotificationsFilters.tsx b/plugins/notifications/src/components/NotificationsFilters/NotificationsFilters.tsx index 3e3a2f3b0f..0cb88bb3f8 100644 --- a/plugins/notifications/src/components/NotificationsFilters/NotificationsFilters.tsx +++ b/plugins/notifications/src/components/NotificationsFilters/NotificationsFilters.tsx @@ -197,9 +197,9 @@ export const NotificationsFilters = ({ value={viewValue} onChange={handleOnViewChanged} > - New only + Unread notifications + Read notifications Saved - Marked as read All diff --git a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx index 22ce11db69..105318564e 100644 --- a/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx +++ b/plugins/notifications/src/components/NotificationsSideBarItem/NotificationsSideBarItem.tsx @@ -45,6 +45,7 @@ import { SeverityIcon } from '../NotificationsTable/SeverityIcon'; import OpenInNew from '@material-ui/icons/OpenInNew'; import MarkAsReadIcon from '@material-ui/icons/CheckCircle'; import IconButton from '@material-ui/core/IconButton'; +import Chip from '@material-ui/core/Chip'; import { styled } from '@material-ui/core/styles'; const StyledMaterialDesignContent = styled(MaterialDesignContent)( @@ -253,7 +254,8 @@ export const NotificationsSidebarItem = (props?: { } }, [titleCounterEnabled, unreadCount, setNotificationCount]); - // TODO: Figure out if the count can be added to hasNotifications + const count = !error && !!unreadCount ? unreadCount : undefined; + return ( <> {snackbarEnabled && ( @@ -277,11 +279,12 @@ export const NotificationsSidebarItem = (props?: { onClick={() => { requestUserPermission(); }} - hasNotifications={!error && !!unreadCount} text={text} icon={icon} {...restProps} - /> + > + {count && 99 ? '99+' : count} />} + ); }; diff --git a/plugins/org-react/CHANGELOG.md b/plugins/org-react/CHANGELOG.md index a0b836c789..2cdb42440f 100644 --- a/plugins/org-react/CHANGELOG.md +++ b/plugins/org-react/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-org-react +## 0.1.33-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + +## 0.1.33-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + +## 0.1.33-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + +## 0.1.31 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + ## 0.1.31-next.3 ### Patch Changes diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json index d4272ce4bb..7317cdf019 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.31-next.3", + "version": "0.1.33-next.2", "backstage": { "role": "web-library", "pluginId": "org", diff --git a/plugins/org/CHANGELOG.md b/plugins/org/CHANGELOG.md index 9eaccb40e8..090168e075 100644 --- a/plugins/org/CHANGELOG.md +++ b/plugins/org/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-org +## 0.6.34-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/plugin-catalog-common@1.1.2-next.0 + +## 0.6.34-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.6.34-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/plugin-catalog-common@1.1.1 + +## 0.6.32 + +### Patch Changes + +- a278fdd: Fix rendering of description in MembersListCard. Add guardrails for potential long texts to prevent it from breaking the UI. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-catalog-common@1.1.1 + ## 0.6.32-next.3 ### Patch Changes diff --git a/plugins/org/package.json b/plugins/org/package.json index 898520bcdd..d5efb6d5d8 100644 --- a/plugins/org/package.json +++ b/plugins/org/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-org", - "version": "0.6.32-next.3", + "version": "0.6.34-next.2", "description": "A Backstage plugin that helps you create entity pages for your organization", "backstage": { "role": "frontend-plugin", diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index a54ee201c5..eff8a44015 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -112,7 +112,9 @@ const MemberComponent = (props: { member: UserEntity }) => { )} {description && ( - {description} + + + )}
diff --git a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md index e785da8f98..71f4a57fdc 100644 --- a/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md +++ b/plugins/permission-backend-module-policy-allow-all/CHANGELOG.md @@ -1,5 +1,45 @@ # @backstage/plugin-permission-backend-module-allow-all-policy +## 0.2.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.2.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.5 + ## 0.2.2-next.2 ### 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 18b5f334d9..8ec39d74c7 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.2-next.2", + "version": "0.2.3-next.2", "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 b1052dae4d..ba1968408a 100644 --- a/plugins/permission-backend/CHANGELOG.md +++ b/plugins/permission-backend/CHANGELOG.md @@ -1,5 +1,55 @@ # @backstage/plugin-permission-backend +## 0.5.52-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.5.52-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## 0.5.52-next.0 + +### Patch Changes + +- 1e624ca: Restrict `@types/express` version range from `*` to `^4.17.6`. +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + +## 0.5.51 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + ## 0.5.51-next.2 ### Patch Changes diff --git a/plugins/permission-backend/package.json b/plugins/permission-backend/package.json index ed0b73c929..b358be1cb7 100644 --- a/plugins/permission-backend/package.json +++ b/plugins/permission-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-backend", - "version": "0.5.51-next.2", + "version": "0.5.52-next.2", "backstage": { "role": "backend-plugin", "pluginId": "permission", @@ -58,12 +58,11 @@ "@backstage/plugin-auth-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", - "@types/express": "*", + "@types/express": "^4.17.6", "dataloader": "^2.0.0", "express": "^4.17.1", "express-promise-router": "^4.1.0", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "yn": "^4.0.0", "zod": "^3.22.4" }, diff --git a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts index 767c7e9dd1..21d2f66887 100644 --- a/plugins/permission-backend/src/service/PermissionIntegrationClient.ts +++ b/plugins/permission-backend/src/service/PermissionIntegrationClient.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import fetch from 'node-fetch'; import { z } from 'zod'; import { AuthorizeResult, diff --git a/plugins/permission-common/CHANGELOG.md b/plugins/permission-common/CHANGELOG.md index b485e9454f..7731cc583e 100644 --- a/plugins/permission-common/CHANGELOG.md +++ b/plugins/permission-common/CHANGELOG.md @@ -1,5 +1,24 @@ # @backstage/plugin-permission-common +## 0.8.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.8.2 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/errors@1.2.5 + ## 0.8.1 ### Patch Changes diff --git a/plugins/permission-common/package.json b/plugins/permission-common/package.json index 145bfe60c3..5ed838a42f 100644 --- a/plugins/permission-common/package.json +++ b/plugins/permission-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-common", - "version": "0.8.1", + "version": "0.8.3-next.0", "description": "Isomorphic types and client for Backstage permissions and authorization", "backstage": { "role": "common-library", diff --git a/plugins/permission-node/CHANGELOG.md b/plugins/permission-node/CHANGELOG.md index 0113abb884..a99a573ad1 100644 --- a/plugins/permission-node/CHANGELOG.md +++ b/plugins/permission-node/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-permission-node +## 0.8.6-next.2 + +### Patch Changes + +- b149e2a: The `createPermissionIntegrationRouter` function now detects and prevents the exposure of duplicate permissions. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.8.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## 0.8.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + +## 0.8.5 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + ## 0.8.5-next.2 ### Patch Changes diff --git a/plugins/permission-node/package.json b/plugins/permission-node/package.json index 39c00d4564..631006daee 100644 --- a/plugins/permission-node/package.json +++ b/plugins/permission-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-permission-node", - "version": "0.8.5-next.2", + "version": "0.8.6-next.2", "description": "Common permission and authorization utilities for backend plugins", "backstage": { "role": "node-library", diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts index 24e1b91065..a38059e547 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.test.ts @@ -904,7 +904,7 @@ describe('createPermissionIntegrationRouter', () => { const response = await request( express().use( createPermissionIntegrationRouter({ - permissions: [aPermission], + permissions: [aPermission, testPermission], resources: [ { resourceType: 'test-resource', diff --git a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts index 40d215d515..5210e6fb1c 100644 --- a/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts +++ b/plugins/permission-node/src/integration/createPermissionIntegrationRouter.ts @@ -328,11 +328,16 @@ export function createPermissionIntegrationRouter< > ).rules || [], ); - const allPermissions = [ - ...((options as { permissions: Permission[] }).permissions || []), - ...(optionsWithResources.resources?.flatMap(o => o.permissions || []) || - []), - ]; + + const allPermissions = Array.from( + new Map( + [ + ...((options as { permissions: Permission[] }).permissions || []), + ...(optionsWithResources.resources?.flatMap(o => o.permissions || []) || + []), + ].map(i => [i.name, i]), + ).values(), + ); const allResourceTypes = allOptions.reduce((acc, option) => { if ( diff --git a/plugins/permission-react/CHANGELOG.md b/plugins/permission-react/CHANGELOG.md index c049a01855..fa68a10367 100644 --- a/plugins/permission-react/CHANGELOG.md +++ b/plugins/permission-react/CHANGELOG.md @@ -1,5 +1,23 @@ # @backstage/plugin-permission-react +## 0.4.29-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.1-next.0 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 0.4.28 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/core-plugin-api@1.10.1 + ## 0.4.27 ### Patch Changes diff --git a/plugins/permission-react/package.json b/plugins/permission-react/package.json index dc452594df..6d7fe9af18 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.27", + "version": "0.4.29-next.0", "backstage": { "role": "web-library", "pluginId": "permission", diff --git a/plugins/proxy-backend/CHANGELOG.md b/plugins/proxy-backend/CHANGELOG.md index b00ff80d9d..2fe259d217 100644 --- a/plugins/proxy-backend/CHANGELOG.md +++ b/plugins/proxy-backend/CHANGELOG.md @@ -1,5 +1,43 @@ # @backstage/plugin-proxy-backend +## 0.5.9-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + +## 0.5.9-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## 0.5.9-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + +## 0.5.8 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + ## 0.5.8-next.2 ### Patch Changes diff --git a/plugins/proxy-backend/package.json b/plugins/proxy-backend/package.json index d60f97cc87..90e52a1367 100644 --- a/plugins/proxy-backend/package.json +++ b/plugins/proxy-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-proxy-backend", - "version": "0.5.8-next.2", + "version": "0.5.9-next.2", "description": "A Backstage backend plugin that helps you set up proxy endpoints in the backend", "backstage": { "role": "backend-plugin", @@ -77,8 +77,7 @@ "@backstage/errors": "workspace:^", "@types/http-proxy-middleware": "^1.0.0", "@types/yup": "^0.32.0", - "msw": "^2.0.0", - "node-fetch": "^2.7.0" + "msw": "^2.0.0" }, "configSchema": "config.d.ts" } diff --git a/plugins/proxy-backend/src/service/router.config.test.ts b/plugins/proxy-backend/src/service/router.config.test.ts index be26ddb9bc..d862107e00 100644 --- a/plugins/proxy-backend/src/service/router.config.test.ts +++ b/plugins/proxy-backend/src/service/router.config.test.ts @@ -29,7 +29,6 @@ import { } from '@backstage/config-loader'; import { HttpResponse, http, passthrough } from 'msw'; import { setupServer } from 'msw/node'; -import fetch from 'node-fetch'; // this test is stored in its own file to work around the mocked // http-proxy-middleware module used in the main test file diff --git a/plugins/proxy-backend/src/service/router.credentials.test.ts b/plugins/proxy-backend/src/service/router.credentials.test.ts index a48b18e8e2..6d1f529b30 100644 --- a/plugins/proxy-backend/src/service/router.credentials.test.ts +++ b/plugins/proxy-backend/src/service/router.credentials.test.ts @@ -25,7 +25,6 @@ import { ResponseError } from '@backstage/errors'; import { JsonObject } from '@backstage/types'; import { HttpResponse, http, passthrough } from 'msw'; import { setupServer } from 'msw/node'; -import fetch from 'node-fetch'; // this test is stored in its own file to work around the mocked // http-proxy-middleware module used in the main test file diff --git a/plugins/scaffolder-backend-module-azure/CHANGELOG.md b/plugins/scaffolder-backend-module-azure/CHANGELOG.md index 75a1967f7f..5fe7df4a13 100644 --- a/plugins/scaffolder-backend-module-azure/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-azure/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-scaffolder-backend-module-azure +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-azure/package.json b/plugins/scaffolder-backend-module-azure/package.json index 4e82a92962..4b3b42046f 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.2-next.3", + "version": "0.2.4-next.2", "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 02d0784690..0bfa509d93 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/CHANGELOG.md @@ -1,5 +1,64 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-cloud +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + +## 0.2.2 + +### Patch Changes + +- 9cf827c: Fix double branch creation in `public:bitbucket{Cloud,Server}:pull-request` + This resulted in the following error when using the actions: + + ``` + AlreadyExistsError: Failed to create branch at create-test because it already exists. + ``` + + The issue was original introduced in d103a48fa306d745599dc0c793668c9e6a479d32 + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/package.json b/plugins/scaffolder-backend-module-bitbucket-cloud/package.json index a645575013..349e6cc60a 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.2-next.3", + "version": "0.2.4-next.2", "description": "The Bitbucket Cloud module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -49,7 +49,6 @@ "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts index 71eacea955..00c27f6a54 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloud.ts @@ -22,7 +22,6 @@ import { getRepoSourceDirectory, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { Response, RequestInit } from 'node-fetch'; import { Config } from '@backstage/config'; import { getAuthorizationHeader } from './helpers'; diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts index c44fdcc824..8525774692 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPipelinesRun.ts @@ -16,7 +16,6 @@ import { examples } from './bitbucketCloudPipelinesRun.examples'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import fetch, { Response } from 'node-fetch'; import * as inputProps from './inputProperties'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { getAuthorizationHeader } from './helpers'; diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts index 99a78c7c26..c70089abc2 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/actions/bitbucketCloudPullRequest.ts @@ -24,7 +24,6 @@ import { cloneRepo, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { RequestInit, Response } from 'node-fetch'; import { Config } from '@backstage/config'; import fs from 'fs-extra'; import { getAuthorizationHeader } from './helpers'; diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts index d99a8358b9..10b277963b 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.test.ts @@ -14,26 +14,40 @@ * limitations under the License. */ +import { InputError } from '@backstage/errors'; import { BitbucketCloudClient } from '@backstage/plugin-bitbucket-cloud-common'; import { handleAutocompleteRequest } from './autocomplete'; -import { InputError } from '@backstage/errors'; describe('handleAutocompleteRequest', () => { const client: Partial = { listWorkspaces: jest.fn().mockReturnValue({ - iteratePages: jest - .fn() - .mockReturnValue([{ values: [{ slug: 'workspace1' }] }]), + iteratePages: jest.fn().mockReturnValue([ + { + values: [ + { + slug: 'workspace1', + }, + ], + }, + ]), }), listProjectsByWorkspace: jest.fn().mockReturnValue({ - iteratePages: jest - .fn() - .mockReturnValue([{ values: [{ key: 'project1' }] }]), + iteratePages: jest.fn().mockReturnValue([ + { + values: [{ key: 'project1' }], + }, + ]), }), listRepositoriesByWorkspace: jest.fn().mockReturnValue({ - iteratePages: jest - .fn() - .mockReturnValue([{ values: [{ slug: 'repository1' }] }]), + iteratePages: jest.fn().mockReturnValue([ + { + values: [ + { + slug: 'repository1', + }, + ], + }, + ]), }), listBranchesByRepository: jest.fn().mockReturnValue({ iteratePages: jest @@ -66,7 +80,9 @@ describe('handleAutocompleteRequest', () => { resource: 'workspaces', }); - expect(result).toEqual({ results: [{ title: 'workspace1' }] }); + expect(result).toEqual({ + results: [{ id: 'workspace1' }], + }); }); it('should return projects', async () => { @@ -78,7 +94,9 @@ describe('handleAutocompleteRequest', () => { resource: 'projects', }); - expect(result).toEqual({ results: [{ title: 'project1' }] }); + expect(result).toEqual({ + results: [{ id: 'project1' }], + }); }); it('should return repositories', async () => { @@ -91,7 +109,9 @@ describe('handleAutocompleteRequest', () => { }, }); - expect(result).toEqual({ results: [{ title: 'repository1' }] }); + expect(result).toEqual({ + results: [{ id: 'repository1' }], + }); }); it('should return branches', async () => { @@ -104,7 +124,7 @@ describe('handleAutocompleteRequest', () => { }, }); - expect(result).toEqual({ results: [{ title: 'branch1' }] }); + expect(result).toEqual({ results: [{ id: 'branch1' }] }); }); it('should throw an error when passing an invalid resource', async () => { diff --git a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts index 75cc170a30..3d1cdd5748 100644 --- a/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts +++ b/plugins/scaffolder-backend-module-bitbucket-cloud/src/autocomplete/autocomplete.ts @@ -25,7 +25,7 @@ export async function handleAutocompleteRequest({ resource: string; token: string; context: Record; -}): Promise<{ results: { title: string }[] }> { +}): Promise<{ results: { title?: string; id: string }[] }> { const client = BitbucketCloudClient.fromConfig({ host: 'bitbucket.org', apiBaseUrl: 'https://api.bitbucket.org/2.0', @@ -34,10 +34,12 @@ export async function handleAutocompleteRequest({ switch (resource) { case 'workspaces': { - const results: { title: string }[] = []; + const results: { title?: string; id: string }[] = []; for await (const page of client.listWorkspaces().iteratePages()) { - const slugs = [...page.values!].map(p => ({ title: p.slug! })); + const slugs = [...page.values!].map(p => ({ + id: p.slug!, + })); results.push(...slugs); } @@ -47,12 +49,14 @@ export async function handleAutocompleteRequest({ if (!context.workspace) throw new InputError('Missing workspace context parameter'); - const results: { title: string }[] = []; + const results: { title?: string; id: string }[] = []; for await (const page of client .listProjectsByWorkspace(context.workspace) .iteratePages()) { - const keys = [...page.values!].map(p => ({ title: p.key! })); + const keys = [...page.values!].map(p => ({ + id: p.key!, + })); results.push(...keys); } @@ -64,14 +68,16 @@ export async function handleAutocompleteRequest({ 'Missing workspace and/or project context parameter', ); - const results: { title: string }[] = []; + const results: { title?: string; id: string }[] = []; for await (const page of client .listRepositoriesByWorkspace(context.workspace, { q: `project.key="${context.project}"`, }) .iteratePages()) { - const slugs = [...page.values!].map(p => ({ title: p.slug! })); + const slugs = [...page.values!].map(p => ({ + id: p.slug!, + })); results.push(...slugs); } @@ -83,12 +89,14 @@ export async function handleAutocompleteRequest({ 'Missing workspace and/or repository context parameter', ); - const results: { title: string }[] = []; + const results: { title?: string; id: string }[] = []; for await (const page of client .listBranchesByRepository(context.repository, context.workspace) .iteratePages()) { - const names = [...page.values!].map(p => ({ title: p.name! })); + const names = [...page.values!].map(p => ({ + id: p.name!, + })); results.push(...names); } diff --git a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md index 300eba0e6a..af3ec86cb8 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket-server/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket-server +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- 9cf827c: Fix double branch creation in `public:bitbucket{Cloud,Server}:pull-request` + This resulted in the following error when using the actions: + + ``` + AlreadyExistsError: Failed to create branch at create-test because it already exists. + ``` + + The issue was original introduced in d103a48fa306d745599dc0c793668c9e6a479d32 + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket-server/package.json b/plugins/scaffolder-backend-module-bitbucket-server/package.json index b7c19ac420..ef35f60c72 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.2-next.3", + "version": "0.2.4-next.2", "description": "The Bitbucket Server module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -48,7 +48,6 @@ "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.ts index 413984aff5..612d090547 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServer.ts @@ -25,7 +25,6 @@ import { getRepoSourceDirectory, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { Response, RequestInit } from 'node-fetch'; import { Config } from '@backstage/config'; import { examples } from './bitbucketServer.examples'; diff --git a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts index 69e9dfe7bf..5b00f15ac2 100644 --- a/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts +++ b/plugins/scaffolder-backend-module-bitbucket-server/src/actions/bitbucketServerPullRequest.ts @@ -27,7 +27,6 @@ import { cloneRepo, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { RequestInit, Response } from 'node-fetch'; import { Config } from '@backstage/config'; import fs from 'fs-extra'; import { examples } from './bitbucketServerPullRequest.examples'; diff --git a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md index 7d05f0992a..f56a30d4ed 100644 --- a/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-bitbucket/CHANGELOG.md @@ -1,5 +1,59 @@ # @backstage/plugin-scaffolder-backend-module-bitbucket +## 0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.3.5-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.3.4-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.3-next.0 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.3.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-bitbucket/package.json b/plugins/scaffolder-backend-module-bitbucket/package.json index 4ad57d7bee..d89b8c660d 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.2-next.3", + "version": "0.3.5-next.2", "description": "The bitbucket module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -50,7 +50,6 @@ "@backstage/plugin-scaffolder-backend-module-bitbucket-server": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", - "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts index f1b45111b4..7a58efa10a 100644 --- a/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts +++ b/plugins/scaffolder-backend-module-bitbucket/src/actions/bitbucket.ts @@ -25,7 +25,6 @@ import { getRepoSourceDirectory, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { Response, RequestInit } from 'node-fetch'; import { Config } from '@backstage/config'; import { examples } from './bitbucket.examples'; diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md index c8303865eb..abb3df3b1b 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-confluence-to-markdown +## 0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.3.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.3.2-next.3 ### 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 e1b315943e..099f9e4bf9 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.2-next.3", + "version": "0.3.4-next.2", "description": "The confluence-to-markdown module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -53,7 +53,6 @@ "@backstage/plugin-scaffolder-node": "workspace:^", "fs-extra": "^11.2.0", "git-url-parse": "^15.0.0", - "node-fetch": "^2.7.0", "node-html-markdown": "^1.3.0", "yaml": "^2.0.0" }, diff --git a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts index 65992b10f3..bbc722b1d5 100644 --- a/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts +++ b/plugins/scaffolder-backend-module-confluence-to-markdown/src/actions/confluence/helpers.ts @@ -17,7 +17,7 @@ import { Config } from '@backstage/config'; import { ResponseError, ConflictError, InputError } from '@backstage/errors'; import fs from 'fs-extra'; -import fetch, { Response } from 'node-fetch'; +import { Readable } from 'stream'; interface Links { webui: string; @@ -164,7 +164,9 @@ export const getAndWriteAttachments = async ( const writeStream = fs.createWriteStream( `${workspace}/${mkdocsDir}docs/img/${downloadTitle}`, ); - res.body.pipe(writeStream); + // TODO(freben): This cast is sketchy, but for some reason the node types don't quite line up here + // https://stackoverflow.com/questions/44672942/stream-response-to-file-using-fetch-api-and-fs-createwritestream/73879265#73879265 + Readable.fromWeb(res.body as any).pipe(writeStream); await new Promise((resolve, reject) => { writeStream.on('finish', () => { resolve(`${workspace}/${mkdocsDir}docs/img/${downloadTitle}`); diff --git a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md index 41f4233fff..942a2b2684 100644 --- a/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-cookiecutter/CHANGELOG.md @@ -1,5 +1,57 @@ # @backstage/plugin-scaffolder-backend-module-cookiecutter +## 0.3.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + +## 0.3.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.3.3 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.3.3-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-cookiecutter/package.json b/plugins/scaffolder-backend-module-cookiecutter/package.json index 8984b735fc..c36132c064 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.3-next.3", + "version": "0.3.5-next.2", "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 c8bef98aa4..cd7a705579 100644 --- a/plugins/scaffolder-backend-module-gcp/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gcp/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-scaffolder-backend-module-gcp +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gcp/package.json b/plugins/scaffolder-backend-module-gcp/package.json index 0b1396e1d0..d3ab1865d2 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.2-next.3", + "version": "0.2.4-next.2", "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 d7555cc6c9..0d393f9a93 100644 --- a/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gerrit/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-gerrit +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gerrit/package.json b/plugins/scaffolder-backend-module-gerrit/package.json index 4f2a4c1ece..1aacbdbaaf 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.2-next.3", + "version": "0.2.4-next.2", "description": "The gerrit module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -47,7 +47,6 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts index 102d48a706..db0ae2ba70 100644 --- a/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts +++ b/plugins/scaffolder-backend-module-gerrit/src/actions/gerrit.ts @@ -28,7 +28,6 @@ import { getRepoSourceDirectory, parseRepoUrl, } from '@backstage/plugin-scaffolder-node'; -import fetch, { Response, RequestInit } from 'node-fetch'; import { examples } from './gerrit.examples'; const createGerritProject = async ( diff --git a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md index 77d0831c4e..793f1ef556 100644 --- a/plugins/scaffolder-backend-module-gitea/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitea/CHANGELOG.md @@ -1,5 +1,50 @@ # @backstage/plugin-scaffolder-backend-module-gitea +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitea/package.json b/plugins/scaffolder-backend-module-gitea/package.json index 3abebdbcba..db2104ac36 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.2-next.3", + "version": "0.2.4-next.2", "description": "The gitea module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", @@ -47,7 +47,6 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.7.0", "yaml": "^2.0.0" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts index 601a670237..6b29ff2a4c 100644 --- a/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts +++ b/plugins/scaffolder-backend-module-gitea/src/actions/gitea.ts @@ -30,7 +30,6 @@ import { } from '@backstage/plugin-scaffolder-node'; import { examples } from './gitea.examples'; import crypto from 'crypto'; -import fetch, { Response, RequestInit } from 'node-fetch'; const checkGiteaContentUrl = async ( config: GiteaIntegrationConfig, diff --git a/plugins/scaffolder-backend-module-github/CHANGELOG.md b/plugins/scaffolder-backend-module-github/CHANGELOG.md index d06806c409..0cb2dd5d70 100644 --- a/plugins/scaffolder-backend-module-github/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-github/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-scaffolder-backend-module-github +## 0.5.4-next.2 + +### Patch Changes + +- e913fdf: Add github backend module to create-app and improve error messages +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.5.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.5.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-github/package.json b/plugins/scaffolder-backend-module-github/package.json index 2525092411..13d5af409a 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.5.2-next.3", + "version": "0.5.4-next.2", "description": "The github module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/scaffolder-backend-module-github/report.api.md b/plugins/scaffolder-backend-module-github/report.api.md index 547c61768f..60ed9db5ef 100644 --- a/plugins/scaffolder-backend-module-github/report.api.md +++ b/plugins/scaffolder-backend-module-github/report.api.md @@ -3,6 +3,7 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AuthService } from '@backstage/backend-plugin-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; import { CatalogApi } from '@backstage/catalog-client'; import { Config } from '@backstage/config'; @@ -79,6 +80,7 @@ export function createGithubBranchProtectionAction(options: { requiredConversationResolution?: boolean | undefined; requireLastPushApproval?: boolean | undefined; requiredCommitSigning?: boolean | undefined; + requiredLinearHistory?: boolean | undefined; token?: string | undefined; }, JsonObject @@ -103,6 +105,7 @@ export function createGithubDeployKeyAction(options: { export function createGithubEnvironmentAction(options: { integrations: ScmIntegrationRegistry; catalogClient?: CatalogApi; + auth?: AuthService; }): TemplateAction< { repoUrl: string; @@ -270,6 +273,7 @@ export function createGithubRepoCreateAction(options: { } | undefined; requireCommitSigning?: boolean | undefined; + requiredLinearHistory?: boolean | undefined; customProperties?: | { [key: string]: string; @@ -317,6 +321,7 @@ export function createGithubRepoPushAction(options: { sourcePath?: string | undefined; token?: string | undefined; requiredCommitSigning?: boolean | undefined; + requiredLinearHistory?: boolean | undefined; requireLastPushApproval?: boolean | undefined; }, JsonObject @@ -430,6 +435,7 @@ export function createPublishGithubAction(options: { } | undefined; requiredCommitSigning?: boolean | undefined; + requiredLinearHistory?: boolean | undefined; customProperties?: | { [key: string]: string; diff --git a/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts index 9989a80724..c720690ee6 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/gitHelpers.ts @@ -43,6 +43,7 @@ type BranchProtectionOptions = { enforceAdmins?: boolean; dismissStaleReviews?: boolean; requiredCommitSigning?: boolean; + requiredLinearHistory?: boolean; }; export const enableBranchProtectionOnDefaultRepoBranch = async ({ @@ -62,6 +63,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ enforceAdmins = true, dismissStaleReviews = false, requiredCommitSigning = false, + requiredLinearHistory = false, }: BranchProtectionOptions): Promise => { const tryOnce = async () => { try { @@ -93,6 +95,7 @@ export const enableBranchProtectionOnDefaultRepoBranch = async ({ require_last_push_approval: requireLastPushApproval, }, required_conversation_resolution: requiredConversationResolution, + required_linear_history: requiredLinearHistory, }); if (requiredCommitSigning) { diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts index 3af922eb4f..f2f36e263a 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.test.ts @@ -1097,6 +1097,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1126,6 +1127,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1154,6 +1156,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1181,6 +1184,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); }); @@ -1269,6 +1273,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1302,6 +1307,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1335,6 +1341,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1370,6 +1377,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1405,6 +1413,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1440,6 +1449,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); }); it('should call enableBranchProtectionOnDefaultRepoBranch with the correct values of bypassPullRequestAllowances', async () => { @@ -1472,6 +1482,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1503,6 +1514,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1534,6 +1546,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1565,6 +1578,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1600,6 +1614,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); await action.handler({ @@ -1635,6 +1650,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, }); }); @@ -1664,6 +1680,11 @@ describe('publish:github', () => { defaultValue: false, overrideValue: true, }, + { + inputProperty: 'requiredLinearHistory', + defaultValue: false, + overrideValue: true, + }, { inputProperty: 'protectEnforceAdmins', defaultValue: true, @@ -1712,6 +1733,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, [octokitParameter || inputProperty]: defaultValue, }); @@ -1740,6 +1762,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, [octokitParameter || inputProperty]: overrideValue, }); @@ -1768,6 +1791,7 @@ describe('publish:github', () => { enforceAdmins: true, dismissStaleReviews: false, requiredCommitSigning: false, + requiredLinearHistory: false, [octokitParameter || inputProperty]: defaultValue, }); }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/github.ts b/plugins/scaffolder-backend-module-github/src/actions/github.ts index 982c68d80f..6d8e0046c2 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/github.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/github.ts @@ -115,6 +115,7 @@ export function createPublishGithubAction(options: { includeClaimKeys?: string[]; }; requiredCommitSigning?: boolean; + requiredLinearHistory?: boolean; customProperties?: { [key: string]: string }; }>({ id: 'publish:github', @@ -165,6 +166,7 @@ export function createPublishGithubAction(options: { secrets: inputProps.secrets, oidcCustomization: inputProps.oidcCustomization, requiredCommitSigning: inputProps.requiredCommitSigning, + requiredLinearHistory: inputProps.requiredLinearHistory, customProperties: inputProps.customProperties, }, }, @@ -217,6 +219,7 @@ export function createPublishGithubAction(options: { token: providedToken, customProperties, requiredCommitSigning = false, + requiredLinearHistory = false, } = ctx.input; const octokitOptions = await getOctokitOptions({ @@ -289,6 +292,7 @@ export function createPublishGithubAction(options: { gitAuthorEmail, dismissStaleReviews, requiredCommitSigning, + requiredLinearHistory, ); ctx.output('commitHash', commitResult?.commitHash); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.test.ts index 5443d7304c..14ebc9a1cd 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.test.ts @@ -98,6 +98,7 @@ describe('github:branch-protection:create', () => { require_last_push_approval: false, }, required_conversation_resolution: false, + required_linear_history: false, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, @@ -130,6 +131,7 @@ describe('github:branch-protection:create', () => { require_last_push_approval: false, }, required_conversation_resolution: false, + required_linear_history: false, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, @@ -162,6 +164,44 @@ describe('github:branch-protection:create', () => { require_last_push_approval: true, }, required_conversation_resolution: true, + required_linear_history: false, + }); + expect( + mockOctokit.rest.repos.createCommitSignatureProtection, + ).toHaveBeenCalledWith({ + owner: 'owner', + repo: 'repo', + branch: 'master', + }); + }); + + it('should create branch protection with params and require linear history', async () => { + const input = yaml.parse(examples[3].example).steps[0].input; + const ctx = Object.assign({}, mockContext, { input }); + await action.handler(ctx); + + expect(mockOctokit.rest.repos.updateBranchProtection).toHaveBeenCalledWith({ + mediaType: { + previews: ['luke-cage-preview'], + }, + owner: 'owner', + repo: 'repo', + branch: 'master', + required_status_checks: { + strict: true, + contexts: ['test'], + }, + restrictions: null, + enforce_admins: true, + required_pull_request_reviews: { + required_approving_review_count: 1, + require_code_owner_reviews: true, + bypass_pull_request_allowances: undefined, + dismiss_stale_reviews: true, + require_last_push_approval: true, + }, + required_conversation_resolution: true, + required_linear_history: true, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.ts index 4d0eb253ef..12761a2b70 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.examples.ts @@ -67,4 +67,25 @@ export const examples: TemplateExample[] = [ ], }), }, + { + description: `GitHub Branch Protection and required linear history on default branch.`, + example: yaml.stringify({ + steps: [ + { + action: 'github:branch-protection:create', + name: 'Setup Branch Protection', + input: { + repoUrl: 'github.com?repo=repo&owner=owner', + requireCodeOwnerReviews: true, + requiredStatusCheckContexts: ['test'], + dismissStaleReviews: true, + requireLastPushApproval: true, + requiredConversationResolution: true, + requiredCommitSigning: true, + requiredLinearHistory: true, + }, + }, + ], + }), + }, ]; diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts index d4eac30b81..8e672af725 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.test.ts @@ -96,6 +96,7 @@ describe('github:branch-protection:create', () => { require_last_push_approval: false, }, required_conversation_resolution: false, + required_linear_history: false, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, @@ -132,6 +133,7 @@ describe('github:branch-protection:create', () => { require_last_push_approval: false, }, required_conversation_resolution: false, + required_linear_history: false, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, @@ -167,6 +169,7 @@ describe('github:branch-protection:create', () => { requiredConversationResolution: true, requireLastPushApproval: true, requiredCommitSigning: true, + requiredLinearHistory: true, }, }); @@ -199,6 +202,7 @@ describe('github:branch-protection:create', () => { require_last_push_approval: true, }, required_conversation_resolution: true, + required_linear_history: true, }); expect( mockOctokit.rest.repos.createCommitSignatureProtection, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts index 4ab847c98e..a7555d3af1 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubBranchProtection.ts @@ -62,6 +62,7 @@ export function createGithubBranchProtectionAction(options: { requiredConversationResolution?: boolean; requireLastPushApproval?: boolean; requiredCommitSigning?: boolean; + requiredLinearHistory?: boolean; token?: string; }>({ id: 'github:branch-protection:create', @@ -90,6 +91,7 @@ export function createGithubBranchProtectionAction(options: { inputProps.requiredConversationResolution, requireLastPushApproval: inputProps.requireLastPushApproval, requiredCommitSigning: inputProps.requiredCommitSigning, + requiredLinearHistory: inputProps.requiredLinearHistory, token: inputProps.token, }, }, @@ -109,6 +111,7 @@ export function createGithubBranchProtectionAction(options: { requiredConversationResolution = false, requireLastPushApproval = false, requiredCommitSigning = false, + requiredLinearHistory = false, token: providedToken, } = ctx.input; @@ -147,6 +150,7 @@ export function createGithubBranchProtectionAction(options: { enforceAdmins, dismissStaleReviews, requiredCommitSigning, + requiredLinearHistory, }); }, }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts index 1397942a7c..898e1842f7 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.test.ts @@ -20,6 +20,7 @@ import { TemplateAction } from '@backstage/plugin-scaffolder-node'; import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; import { CatalogApi } from '@backstage/catalog-client'; +import { mockCredentials, mockServices } from '@backstage/backend-test-utils'; const mockOctokit = { rest: { @@ -71,6 +72,14 @@ describe('github:environment:create', () => { }); const integrations = ScmIntegrations.fromConfig(config); + + const credentials = mockCredentials.user(); + + const token = mockCredentials.service.token({ + onBehalfOf: credentials, + targetPluginId: 'catalog', + }); + let action: TemplateAction; const mockContext = createMockActionContext({ @@ -78,6 +87,7 @@ describe('github:environment:create', () => { repoUrl: 'github.com?repo=repository&owner=owner', name: 'envname', }, + secrets: { backstageToken: token }, }); beforeEach(() => { @@ -122,6 +132,7 @@ describe('github:environment:create', () => { action = createGithubEnvironmentAction({ integrations, catalogClient: mockCatalogClient as CatalogApi, + auth: mockServices.auth(), }); }); @@ -453,6 +464,13 @@ describe('github:environment:create', () => { }, }); + expect(mockCatalogClient.getEntitiesByRefs).toHaveBeenCalledWith( + { + entityRefs: ['group:default/team-a', 'user:default/johndoe'], + }, + { token }, + ); + expect( mockOctokit.rest.repos.createOrUpdateEnvironment, ).toHaveBeenCalledWith({ diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts index 29c0a3ce38..ef59b611fe 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubEnvironment.ts @@ -26,6 +26,7 @@ import Sodium from 'libsodium-wrappers'; import { examples } from './gitHubEnvironment.examples'; import { CatalogApi } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; +import { AuthService } from '@backstage/backend-plugin-api'; /** * Creates an `github:environment:create` Scaffolder action that creates a Github Environment. @@ -35,8 +36,9 @@ import { Entity } from '@backstage/catalog-model'; export function createGithubEnvironmentAction(options: { integrations: ScmIntegrationRegistry; catalogClient?: CatalogApi; + auth?: AuthService; }) { - const { integrations, catalogClient } = options; + const { integrations, catalogClient, auth } = options; // For more information on how to define custom actions, see // https://backstage.io/docs/features/software-templates/writing-custom-actions return createTemplateAction<{ @@ -140,7 +142,8 @@ export function createGithubEnvironmentAction(options: { reviewers: { title: 'Reviewers', type: 'array', - description: 'Reviewers for this environment', + description: + 'Reviewers for this environment. Must be a list of Backstage entity references.', items: { type: 'string', }, @@ -163,6 +166,11 @@ export function createGithubEnvironmentAction(options: { reviewers, } = ctx.input; + const { token } = (await auth?.getPluginRequestToken({ + onBehalfOf: await ctx.getInitiatorCredentials(), + targetPluginId: 'catalog', + })) ?? { token: ctx.secrets?.backstageToken }; + // When environment creation step is executed right after a repo publish step, the repository might not be available immediately. // Add a 2-second delay before initiating the steps in this action. await new Promise(resolve => setTimeout(resolve, 2000)); @@ -190,9 +198,14 @@ export function createGithubEnvironmentAction(options: { if (reviewers) { let reviewersEntityRefs: Array = []; // Fetch reviewers from Catalog - const catalogResponse = await catalogClient?.getEntitiesByRefs({ - entityRefs: reviewers, - }); + const catalogResponse = await catalogClient?.getEntitiesByRefs( + { + entityRefs: reviewers, + }, + { + token, + }, + ); if (catalogResponse?.items?.length) { reviewersEntityRefs = catalogResponse.items; } diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts index 044005961e..42b9c47030 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubPagesEnable.ts @@ -67,14 +67,13 @@ export function createGithubPagesEnableAction(options: { sourceBranch: { title: 'Source Branch', type: 'string', - description: - 'The the GitHub Pages source branch. Default is "main"', + description: 'The GitHub Pages source branch. Default is "main"', }, sourcePath: { title: 'Source Path', type: 'string', description: - 'The the GitHub Pages source path - "/" or "/docs". Default is "/"', + 'The GitHub Pages source path - "/" or "/docs". Default is "/"', }, token: { title: 'Authorization Token', diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts index 1c3d035ee3..61dea32c35 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoCreate.ts @@ -100,6 +100,7 @@ export function createGithubRepoCreateAction(options: { includeClaimKeys?: string[]; }; requireCommitSigning?: boolean; + requiredLinearHistory?: boolean; customProperties?: { [key: string]: string }; }>({ id: 'github:repo:create', @@ -140,6 +141,7 @@ export function createGithubRepoCreateAction(options: { secrets: inputProps.secrets, oidcCustomization: inputProps.oidcCustomization, requiredCommitSigning: inputProps.requiredCommitSigning, + requiredLinearHistory: inputProps.requiredLinearHistory, customProperties: inputProps.customProperties, }, }, diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts index d0ee4bfa12..9ff8cd123c 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.test.ts @@ -331,6 +331,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, }); @@ -359,6 +360,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, }); @@ -387,6 +389,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, }); @@ -415,6 +418,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, }); }); @@ -464,6 +468,11 @@ describe('github:repo:push', () => { defaultValue: false, overrideValue: true, }, + { + inputProperty: 'requiredLinearHistory', + defaultValue: false, + overrideValue: true, + }, { inputProperty: 'protectEnforceAdmins', defaultValue: true, @@ -508,6 +517,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, [octokitParameter || inputProperty]: defaultValue, }); @@ -536,6 +546,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, [octokitParameter || inputProperty]: overrideValue, }); @@ -564,6 +575,7 @@ describe('github:repo:push', () => { bypassPullRequestAllowances: undefined, requiredApprovingReviewCount: 1, requiredCommitSigning: false, + requiredLinearHistory: false, restrictions: undefined, [octokitParameter || inputProperty]: defaultValue, }); diff --git a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts index a4fa7673c6..62624057c8 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/githubRepoPush.ts @@ -75,6 +75,7 @@ export function createGithubRepoPushAction(options: { sourcePath?: string; token?: string; requiredCommitSigning?: boolean; + requiredLinearHistory?: boolean; requireLastPushApproval?: boolean; }>({ id: 'github:repo:push', @@ -106,6 +107,7 @@ export function createGithubRepoPushAction(options: { sourcePath: inputProps.sourcePath, token: inputProps.token, requiredCommitSigning: inputProps.requiredCommitSigning, + requiredLinearHistory: inputProps.requiredLinearHistory, }, }, output: { @@ -137,6 +139,7 @@ export function createGithubRepoPushAction(options: { requireLastPushApproval = false, token: providedToken, requiredCommitSigning = false, + requiredLinearHistory = false, } = ctx.input; const { owner, repo } = parseRepoUrl(repoUrl, integrations); @@ -185,6 +188,7 @@ export function createGithubRepoPushAction(options: { gitAuthorEmail, dismissStaleReviews, requiredCommitSigning, + requiredLinearHistory, ); ctx.output('remoteUrl', remoteUrl); diff --git a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts index 0ae1cad3fb..9bba0ca359 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/helpers.ts @@ -93,7 +93,7 @@ export async function getOctokitOptions(options: { if (!credentialProviderToken) { throw new InputError( - `No token available for host: ${host}, with owner ${owner}, and repo ${repo}`, + `No token available for host: ${host}, with owner ${owner}, and repo ${repo}. Make sure GitHub auth is configured correctly. See https://backstage.io/docs/auth/github/provider for more details.`, ); } @@ -371,6 +371,7 @@ export async function initRepoPushAndProtect( gitAuthorEmail?: string, dismissStaleReviews?: boolean, requiredCommitSigning?: boolean, + requiredLinearHistory?: boolean, ): Promise<{ commitHash: string }> { const gitAuthorInfo = { name: gitAuthorName @@ -416,6 +417,7 @@ export async function initRepoPushAndProtect( enforceAdmins: protectEnforceAdmins, dismissStaleReviews: dismissStaleReviews, requiredCommitSigning: requiredCommitSigning, + requiredLinearHistory: requiredLinearHistory, }); } catch (e) { assertError(e); diff --git a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts index 4a52c1d69f..2c86cf492e 100644 --- a/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts +++ b/plugins/scaffolder-backend-module-github/src/actions/inputProperties.ts @@ -270,6 +270,12 @@ const requiredCommitSigning = { description: `Require commit signing so that you must sign commits on this branch.`, }; +const requiredLinearHistory = { + title: 'Require linear history', + type: 'boolean', + description: `Prevent merge commits from being pushed to matching branches.`, +}; + const repoVariables = { title: 'Repository Variables', description: `Variables attached to the repository`, @@ -346,6 +352,7 @@ export { sourcePath }; export { token }; export { topics }; export { requiredCommitSigning }; +export { requiredLinearHistory }; export { repoVariables }; export { secrets }; export { oidcCustomization }; diff --git a/plugins/scaffolder-backend-module-github/src/module.ts b/plugins/scaffolder-backend-module-github/src/module.ts index f837ad0456..0387473fdb 100644 --- a/plugins/scaffolder-backend-module-github/src/module.ts +++ b/plugins/scaffolder-backend-module-github/src/module.ts @@ -51,8 +51,9 @@ export const githubModule = createBackendModule({ scaffolder: scaffolderActionsExtensionPoint, config: coreServices.rootConfig, discovery: coreServices.discovery, + auth: coreServices.auth, }, - async init({ scaffolder, config, discovery }) { + async init({ scaffolder, config, discovery, auth }) { const integrations = ScmIntegrations.fromConfig(config); const githubCredentialsProvider = DefaultGithubCredentialsProvider.fromIntegrations(integrations); @@ -75,6 +76,7 @@ export const githubModule = createBackendModule({ createGithubEnvironmentAction({ integrations, catalogClient, + auth, }), createGithubIssuesLabelAction({ integrations, diff --git a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md index 4a4409a64b..87ff348fc6 100644 --- a/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-gitlab/CHANGELOG.md @@ -1,5 +1,56 @@ # @backstage/plugin-scaffolder-backend-module-gitlab +## 0.7.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + +## 0.7.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + +## 0.7.0-next.0 + +### Minor Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 32459d0: **BREAKING**: Upgraded the `gitbeaker` library to version 41. As part of this, the `scopes` parameter to the `gitlab:projectDeployToken:create` is no longer optional, so you will have to pass it a value (for example `['read_repository']`). + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.6.1 + +### Patch Changes + +- cdc8b4c: Improve error messages from Gitlab +- 2dbdccb: Removed circular import +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.6.1-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-gitlab/package.json b/plugins/scaffolder-backend-module-gitlab/package.json index cb5d5f633b..b3244783f9 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.6.1-next.3", + "version": "0.7.0-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", @@ -51,9 +51,7 @@ "@backstage/errors": "workspace:^", "@backstage/integration": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "@gitbeaker/core": "^35.8.0", - "@gitbeaker/node": "^35.8.0", - "@gitbeaker/rest": "^39.25.0", + "@gitbeaker/rest": "^41.2.0", "luxon": "^3.0.0", "winston": "^3.2.1", "yaml": "^2.0.0", diff --git a/plugins/scaffolder-backend-module-gitlab/report.api.md b/plugins/scaffolder-backend-module-gitlab/report.api.md index 0cf1c41717..896c0a5899 100644 --- a/plugins/scaffolder-backend-module-gitlab/report.api.md +++ b/plugins/scaffolder-backend-module-gitlab/report.api.md @@ -76,11 +76,11 @@ export const createGitlabProjectDeployTokenAction: (options: { }) => TemplateAction< { name: string; + scopes: string[]; repoUrl: string; projectId: string | number; username?: string | undefined; token?: string | undefined; - scopes?: string[] | undefined; }, { user: string; @@ -149,8 +149,8 @@ export function createPublishGitlabAction(options: { squash_option?: | 'always' | 'never' - | 'default_off' | 'default_on' + | 'default_off' | undefined; topics?: string[] | undefined; visibility?: 'internal' | 'private' | 'public' | undefined; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts index 4294e5f137..c7a7b01aad 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.examples.test.ts @@ -42,13 +42,13 @@ const mockGitlabClient = { create: jest.fn(), }, Users: { - current: jest.fn(), + showCurrentUser: jest.fn(), }, ProjectMembers: { add: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -86,7 +86,7 @@ describe('publish:gitlab', () => { }); it('should call initRepoAndPush with the correct values', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts index bbcae08063..6e131e91fc 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.test.ts @@ -40,7 +40,7 @@ const mockGitlabClient = { create: jest.fn(), }, Users: { - current: jest.fn(), + showCurrentUser: jest.fn(), }, ProjectMembers: { add: jest.fn(), @@ -55,7 +55,7 @@ const mockGitlabClient = { create: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -183,7 +183,7 @@ describe('publish:gitlab', () => { }); it('should work when there is a token provided through ctx.input', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -199,7 +199,7 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'bob', visibility: 'private', }); @@ -208,7 +208,7 @@ describe('publish:gitlab', () => { }); it('should call the correct Gitlab APIs when the owner is an organization', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -218,7 +218,7 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'repo', visibility: 'private', ci_config_path: '.gitlab-ci.yml', @@ -229,7 +229,7 @@ describe('publish:gitlab', () => { it('should call the correct Gitlab APIs when the owner is not an organization', async () => { mockGitlabClient.Namespaces.show.mockResolvedValue({ id: null }); - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', }); @@ -238,7 +238,7 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 12345, + namespaceId: 12345, name: 'repo', visibility: 'private', ci_config_path: '.gitlab-ci.yml', @@ -248,7 +248,7 @@ describe('publish:gitlab', () => { }); it('should call the correct Gitlab APIs when using project settings with override of visibility and topics', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -258,7 +258,7 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'repo', visibility: 'internal', topics: ['topic1', 'topic2'], @@ -269,7 +269,7 @@ describe('publish:gitlab', () => { }); it('should call the correct Gitlab APIs for branches and protectd branches when branch settings provided', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ id: 123456, @@ -280,7 +280,7 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'repo', visibility: 'private', }); @@ -309,7 +309,7 @@ describe('publish:gitlab', () => { }); it('should call the correct Gitlab APIs for variables when their configuration is provided', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ id: 123456, @@ -320,28 +320,28 @@ describe('publish:gitlab', () => { expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'repo', visibility: 'private', }); expect(mockGitlabClient.ProjectVariables.create).toHaveBeenCalledWith( 123456, + 'key', + 'value', { - key: 'key', - value: 'value', description: 'description', - variable_type: 'env_var', + variableType: 'env_var', protected: true, masked: true, raw: false, - environment_scope: '*', + environmentScope: '*', }, ); }); it('should call initRepoAndPush with the correct values', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -361,7 +361,7 @@ describe('publish:gitlab', () => { }); it('should call initRepoAndPush with the correct default branch', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -416,7 +416,7 @@ describe('publish:gitlab', () => { config: customAuthorConfig, }); - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -462,7 +462,7 @@ describe('publish:gitlab', () => { config: customAuthorConfig, }); - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -482,7 +482,7 @@ describe('publish:gitlab', () => { }); it('should call output with the remoteUrl and repoContentsUrl and projectId', async () => { - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); mockGitlabClient.Projects.create.mockResolvedValue({ http_url_to_repo: 'http://mockurl.git', @@ -523,7 +523,7 @@ describe('publish:gitlab', () => { }); mockGitlabClient.Namespaces.show.mockResolvedValue({ id: 1234 }); - mockGitlabClient.Users.current.mockResolvedValue({ id: 12345 }); + mockGitlabClient.Users.showCurrentUser.mockResolvedValue({ id: 12345 }); mockGitlabClient.Projects.create.mockResolvedValue({ id: 123456, http_url_to_repo: 'http://mockurl.git', @@ -539,14 +539,14 @@ describe('publish:gitlab', () => { }); expect(mockGitlabClient.Namespaces.show).toHaveBeenCalledWith('owner'); - expect(mockGitlabClient.Users.current).toHaveBeenCalled(); + expect(mockGitlabClient.Users.showCurrentUser).toHaveBeenCalled(); expect(mockGitlabClient.ProjectMembers.add).toHaveBeenCalledWith( 123456, 12345, 50, ); expect(mockGitlabClient.Projects.create).toHaveBeenCalledWith({ - namespace_id: 1234, + namespaceId: 1234, name: 'repo', visibility: 'private', }); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts index 957ac0aaf7..c682749f83 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlab.ts @@ -17,7 +17,7 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { Gitlab } from '@gitbeaker/node'; +import { Gitlab, VariableType } from '@gitbeaker/rest'; import { initRepoAndPush, getRepoSourceDirectory, @@ -383,7 +383,7 @@ export function createPublishGitlabAction(options: { throw e; } - const { id: userId } = (await client.Users.current()) as { + const { id: userId } = (await client.Users.showCurrentUser()) as { id: number; }; @@ -392,7 +392,7 @@ export function createPublishGitlabAction(options: { } const { id: projectId, http_url_to_repo } = await client.Projects.create({ - namespace_id: targetNamespaceId, + namespaceId: targetNamespaceId, name: repo, visibility: repoVisibility, ...(topics.length ? { topics } : {}), @@ -478,7 +478,8 @@ export function createPublishGitlabAction(options: { if (projectVariables) { for (const variable of projectVariables) { const variableWithDefaults = Object.assign(variable, { - variable_type: variable.variable_type ?? 'env_var', + variable_type: (variable.variable_type ?? + 'env_var') as VariableType, protected: variable.protected ?? false, masked: variable.masked ?? false, raw: variable.raw ?? false, @@ -488,7 +489,16 @@ export function createPublishGitlabAction(options: { try { await client.ProjectVariables.create( projectId, - variableWithDefaults, + variableWithDefaults.key, + variableWithDefaults.value, + { + variableType: variableWithDefaults.variable_type, + protected: variableWithDefaults.protected, + masked: variableWithDefaults.masked, + environmentScope: variableWithDefaults.environment_scope, + description: variableWithDefaults.description, + raw: variableWithDefaults.raw, + }, ); } catch (e) { throw new InputError( diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts index 41bc5755c9..7134726e6f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabGroupEnsureExists.ts @@ -16,7 +16,7 @@ import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { GroupSchema } from '@gitbeaker/core/dist/types/resources/Groups'; +import { GroupSchema } from '@gitbeaker/rest'; import { z } from 'zod'; import commonGitlabConfig from '../commonGitlabConfig'; import { getClient, parseRepoUrl } from '../util'; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.examples.test.ts index 6f26bc1c68..087d474807 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.examples.test.ts @@ -53,9 +53,10 @@ const mockGitlabClient = { }, Users: { current: jest.fn(), - username: jest.fn(async (user: string) => { + all: jest.fn(async (userOptions: { username: string }) => { const users: string[] = ['John Smith', 'my-assignee']; - if (!users.includes(user)) throw new Error('user does not exist'); + if (!users.includes(userOptions.username)) + throw new Error('user does not exist'); else return [ { @@ -66,7 +67,7 @@ const mockGitlabClient = { }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts index cffa5fd666..b5db1b4811 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.test.ts @@ -66,19 +66,18 @@ const mockGitlabClient = { }), }, Users: { - current: jest.fn(), - username: jest.fn(async (user: string) => { - if (user !== 'John Smith') throw new Error('user does not exist'); - else - return [ - { - id: 123, - }, - ]; + all: jest.fn(async (userOptions: { username: string }) => { + if (userOptions.username !== 'John Smith') + throw new Error('user does not exist'); + return [ + { + id: 123, + }, + ]; }), }, Repositories: { - tree: jest.fn( + allRepositoryTrees: jest.fn( async ( repoID: string | number, options: { ref: string; recursive: boolean; path: string | undefined }, @@ -123,7 +122,7 @@ const mockGitlabClient = { }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts index f2c6bd5723..4e4812fdcf 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabMergeRequest.ts @@ -20,7 +20,7 @@ import { SerializedFile, serializeDirectoryContents, } from '@backstage/plugin-scaffolder-node'; -import { Gitlab, Types } from '@gitbeaker/core'; +import { Gitlab, RepositoryTreeSchema, CommitAction } from '@gitbeaker/rest'; import path from 'path'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; @@ -41,9 +41,9 @@ function computeSha256(file: SerializedFile): string { async function getFileAction( fileInfo: { file: SerializedFile; targetPath?: string }, target: { repoID: string; branch: string }, - api: Gitlab, + api: InstanceType, logger: LoggerService, - remoteFiles: Types.RepositoryTreeSchema[], + remoteFiles: RepositoryTreeSchema[], defaultCommitAction: | 'create' | 'delete' @@ -231,7 +231,7 @@ which uses additional API calls in order to detect whether to 'create', 'update' if (assignee !== undefined) { try { - const assigneeUser = await api.Users.username(assignee); + const assigneeUser = await api.Users.all({ username: assignee }); assigneeId = assigneeUser[0].id; } catch (e) { ctx.logger.warn( @@ -259,15 +259,21 @@ which uses additional API calls in order to detect whether to 'create', 'update' let targetBranch = targetBranchName; if (!targetBranch) { const projects = await api.Projects.show(repoID); - - const { default_branch: defaultBranch } = projects; - targetBranch = defaultBranch!; + const defaultBranch = projects.default_branch ?? projects.defaultBranch; + if (typeof defaultBranch !== 'string' || !defaultBranch) { + throw new InputError( + `The branch creation failed. Target branch was not provided, and could not find default branch from project settings. Project: ${JSON.stringify( + project, + )}`, + ); + } + targetBranch = defaultBranch; } - let remoteFiles: Types.RepositoryTreeSchema[] = []; + let remoteFiles: RepositoryTreeSchema[] = []; if ((ctx.input.commitAction ?? 'auto') === 'auto') { try { - remoteFiles = await api.Repositories.tree(repoID, { + remoteFiles = await api.Repositories.allRepositoryTrees(repoID, { ref: targetBranch, recursive: true, path: targetPath ?? undefined, @@ -280,7 +286,7 @@ which uses additional API calls in order to detect whether to 'create', 'update' ); } } - const actions: Types.CommitAction[] = + const actions: CommitAction[] = ctx.input.commitAction === 'skip' ? [] : ( @@ -300,7 +306,7 @@ which uses additional API calls in order to detect whether to 'create', 'update' ) ).filter(o => o.action !== 'skip') as { file: SerializedFile; - action: Types.CommitAction['action']; + action: CommitAction['action']; }[] ).map(({ file, action }) => ({ action, @@ -359,9 +365,7 @@ which uses additional API calls in order to detect whether to 'create', 'update' removeSourceBranch: removeSourceBranch ? removeSourceBranch : false, assigneeId, }, - ).then((mergeRequest: { web_url: string }) => { - return mergeRequest.web_url; - }); + ).then(mergeRequest => mergeRequest.web_url ?? mergeRequest.webUrl); ctx.output('projectid', repoID); ctx.output('targetBranchName', targetBranch); ctx.output('projectPath', repoID); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts index bdf14ce1c8..3ad0237d76 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.examples.test.ts @@ -13,17 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import yaml from 'yaml'; import { createGitlabProjectAccessTokenAction } from './gitlabProjectAccessTokenCreate'; // Adjust the import based on your project structure import { examples } from './gitlabProjectAccessTokenCreate.examples'; - import { DateTime } from 'luxon'; -jest.mock('node-fetch'); - const mockGitlabClient = { ProjectAccessTokens: { create: jest.fn(), @@ -88,9 +86,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '456', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -113,9 +111,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '789', 'tokenname', ['read_registry', 'write_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -138,9 +136,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'my-custom-token', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -163,9 +161,9 @@ describe('gitlab:projectAccessToken:create examples', () => { 42, 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -188,9 +186,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '123', 'tokenname', ['read_repository'], + '2024-06-25', { accessLevel: 40, - expiresAt: '2024-06-25', }, ); @@ -213,9 +211,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '456', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 30, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -241,9 +239,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '456', 'full-access-token', ['read_repository'], + '2024-12-31', { accessLevel: 40, - expiresAt: '2024-12-31', }, ); @@ -269,9 +267,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -297,9 +295,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository', 'read_api'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -325,9 +323,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 10, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -353,9 +351,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -381,9 +379,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 50, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -409,9 +407,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'no-expiry-token', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -437,9 +435,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '101112', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts index 34ce8878f2..0cbc0fc122 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.test.ts @@ -13,15 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import { ConfigReader } from '@backstage/config'; import { ScmIntegrations } from '@backstage/integration'; import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test-utils'; import { createGitlabProjectAccessTokenAction } from './gitlabProjectAccessTokenCreate'; // Adjust the import based on your project structure - import { DateTime } from 'luxon'; -jest.mock('node-fetch'); - const mockGitlabClient = { ProjectAccessTokens: { create: jest.fn(), @@ -84,9 +82,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '987', 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -115,9 +113,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '987', 'tokenname', ['read_registry', 'write_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -146,9 +144,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '2110', 'token', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -176,9 +174,9 @@ describe('gitlab:projectAccessToken:create examples', () => { 23, 'tokenname', ['read_repository'], + DateTime.now().plus({ days: 365 }).toISODate()!, { accessLevel: 40, - expiresAt: DateTime.now().plus({ days: 365 }).toISODate()!, }, ); @@ -207,9 +205,9 @@ describe('gitlab:projectAccessToken:create examples', () => { '123', 'tokenname', ['read_repository'], + '1999-07-14', { accessLevel: 40, - expiresAt: '1999-07-14', }, ); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.ts index 5d31686a6e..ae1e92214f 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectAccessTokenCreate.ts @@ -108,9 +108,8 @@ export const createGitlabProjectAccessTokenAction = (options: { projectId, name, scopes as AccessTokenScopes[], + expiresAt || DateTime.now().plus({ days: 365 }).toISODate()!, { - expiresAt: - expiresAt || DateTime.now().plus({ days: 365 }).toISODate()!, accessLevel, }, ); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.test.ts index d56d6de556..f94468f856 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.test.ts @@ -22,11 +22,11 @@ import { createGitlabProjectDeployTokenAction } from './gitlabProjectDeployToken import { examples } from './gitlabProjectDeployTokenCreate.examples'; const mockGitlabClient = { - ProjectDeployTokens: { - add: jest.fn(), + DeployTokens: { + create: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -68,7 +68,7 @@ describe('gitlab:create-deploy-token', () => { }); it(`Should ${examples[0].description}`, async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -78,11 +78,13 @@ describe('gitlab:create-deploy-token', () => { input: yaml.parse(examples[0].example).steps[0].input, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - '456', + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'tokenname', - undefined, - { username: undefined }, + ['read_registry'], + { + projectId: '456', + username: undefined, + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); @@ -90,7 +92,7 @@ describe('gitlab:create-deploy-token', () => { }); it(`Should ${examples[1].description}`, async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -100,11 +102,13 @@ describe('gitlab:create-deploy-token', () => { input: yaml.parse(examples[1].example).steps[0].input, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - '789', + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'tokenname', ['read_registry', 'write_repository'], - { username: undefined }, + { + projectId: '789', + username: undefined, + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); @@ -112,7 +116,7 @@ describe('gitlab:create-deploy-token', () => { }); it(`Should ${examples[2].description}`, async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -122,11 +126,13 @@ describe('gitlab:create-deploy-token', () => { input: yaml.parse(examples[2].example).steps[0].input, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - '101112', + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'my-custom-token', - undefined, - { username: undefined }, + ['read_registry'], + { + projectId: '101112', + username: undefined, + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); @@ -134,7 +140,7 @@ describe('gitlab:create-deploy-token', () => { }); it(`Should ${examples[3].description}`, async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -144,11 +150,13 @@ describe('gitlab:create-deploy-token', () => { input: yaml.parse(examples[3].example).steps[0].input, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - 42, + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'tokenname', - undefined, - { username: undefined }, + ['read_registry'], + { + projectId: 42, + username: undefined, + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); @@ -156,7 +164,7 @@ describe('gitlab:create-deploy-token', () => { }); it(`Should ${examples[4].description}`, async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -166,11 +174,13 @@ describe('gitlab:create-deploy-token', () => { input: yaml.parse(examples[4].example).steps[0].input, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - 42, + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'tokenname', - undefined, - { username: 'tokenuser' }, + ['read_registry'], + { + projectId: 42, + username: 'tokenuser', + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.ts index 326747d45a..f306ee191c 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.examples.ts @@ -29,13 +29,15 @@ export const examples: TemplateExample[] = [ repoUrl: 'gitlab.com?repo=repo&owner=owner', projectId: '456', name: 'tokenname', + scopes: ['read_registry'], }, }, ], }), }, { - description: 'Create a GitLab project deploy token with custom scopes.', + description: + 'Create a GitLab project deploy token with many custom scopes.', example: yaml.stringify({ steps: [ { @@ -64,6 +66,7 @@ export const examples: TemplateExample[] = [ repoUrl: 'gitlab.com?repo=repo&owner=owner', projectId: '101112', name: 'my-custom-token', + scopes: ['read_registry'], }, }, ], @@ -82,6 +85,7 @@ export const examples: TemplateExample[] = [ repoUrl: 'gitlab.com?repo=repo&owner=owner', projectId: 42, name: 'tokenname', + scopes: ['read_registry'], }, }, ], @@ -101,6 +105,7 @@ export const examples: TemplateExample[] = [ projectId: 42, name: 'tokenname', username: 'tokenuser', + scopes: ['read_registry'], }, }, ], diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.test.ts index 146692006b..4b1c5b52a1 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.test.ts @@ -20,11 +20,11 @@ import { createMockActionContext } from '@backstage/plugin-scaffolder-node-test- import { createGitlabProjectDeployTokenAction } from './gitlabProjectDeployTokenCreate'; const mockGitlabClient = { - ProjectDeployTokens: { - add: jest.fn(), + DeployTokens: { + create: jest.fn(), }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; @@ -66,7 +66,7 @@ describe('gitlab:create-deploy-token', () => { }); it('should work when there is a token provided through ctx.input', async () => { - mockGitlabClient.ProjectDeployTokens.add.mockResolvedValue({ + mockGitlabClient.DeployTokens.create.mockResolvedValue({ token: 'TOKEN', username: 'User', }); @@ -82,11 +82,13 @@ describe('gitlab:create-deploy-token', () => { }, }); - expect(mockGitlabClient.ProjectDeployTokens.add).toHaveBeenCalledWith( - '123', + expect(mockGitlabClient.DeployTokens.create).toHaveBeenCalledWith( 'tokenname', ['read_repository'], - { username: 'tokenuser' }, + { + projectId: '123', + username: 'tokenuser', + }, ); expect(mockContext.output).toHaveBeenCalledWith('deploy_token', 'TOKEN'); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.ts index 79ecc0de4e..600d982d8d 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabProjectDeployTokenCreate.ts @@ -17,8 +17,7 @@ import { InputError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; -import { DeployTokenScope } from '@gitbeaker/core/dist/types/templates/ResourceDeployTokens'; -import { Gitlab } from '@gitbeaker/node'; +import { DeployTokenScope, Gitlab } from '@gitbeaker/rest'; import { z } from 'zod'; import commonGitlabConfig from '../commonGitlabConfig'; import { getToken } from '../util'; @@ -47,7 +46,7 @@ export const createGitlabProjectDeployTokenAction = (options: { username: z .string({ description: 'Deploy Token Username' }) .optional(), - scopes: z.array(z.string(), { description: 'Scopes' }).optional(), + scopes: z.array(z.string(), { description: 'Scopes' }), }), ), output: z.object({ @@ -60,17 +59,23 @@ export const createGitlabProjectDeployTokenAction = (options: { const { projectId, name, username, scopes } = ctx.input; const { token, integrationConfig } = getToken(ctx.input, integrations); + if (scopes.length === 0) { + throw new InputError( + `Could not create token for project "${ctx.input.projectId}": scopes cannot be empty.`, + ); + } + const api = new Gitlab({ host: integrationConfig.config.baseUrl, token: token, }); - const deployToken = await api.ProjectDeployTokens.add( - projectId, + const deployToken = await api.DeployTokens.create( name, scopes as DeployTokenScope[], { - username: username, + projectId, + username, }, ); diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts index d84181d398..ab3dd528f5 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.examples.test.ts @@ -45,7 +45,7 @@ const mockGitlabClient = { }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts index 569d3c0c56..3204dffaaf 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.test.ts @@ -44,7 +44,7 @@ const mockGitlabClient = { }, }; -jest.mock('@gitbeaker/node', () => ({ +jest.mock('@gitbeaker/rest', () => ({ Gitlab: class { constructor() { return mockGitlabClient; diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts index 2275f605af..089802fea4 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/gitlabRepoPush.ts @@ -19,7 +19,7 @@ import { parseRepoUrl, serializeDirectoryContents, } from '@backstage/plugin-scaffolder-node'; -import { Types } from '@gitbeaker/core'; +import { CommitAction } from '@gitbeaker/rest'; import path from 'path'; import { ScmIntegrationRegistry } from '@backstage/integration'; import { InputError } from '@backstage/errors'; @@ -141,7 +141,7 @@ export const createGitlabRepoPushAction = (options: { gitignore: true, }); - const actions: Types.CommitAction[] = fileContents.map(file => ({ + const actions: CommitAction[] = fileContents.map(file => ({ action: commitAction ?? 'create', filePath: targetPath ? path.posix.join(targetPath, file.path) diff --git a/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts b/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts index 37f587c4d4..7f6dead3ca 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/actions/helpers.ts @@ -15,15 +15,14 @@ */ import { parseRepoUrl } from '@backstage/plugin-scaffolder-node'; import { ErrorLike, InputError, isError } from '@backstage/errors'; -import { Gitlab } from '@gitbeaker/node'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { Resources } from '@gitbeaker/core'; +import { Gitlab } from '@gitbeaker/rest'; export function createGitlabApi(options: { integrations: ScmIntegrationRegistry; token?: string; repoUrl: string; -}): Resources.Gitlab { +}): InstanceType { const { integrations, token: providedToken, repoUrl } = options; const { host } = parseRepoUrl(repoUrl, integrations); diff --git a/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.test.ts b/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.test.ts new file mode 100644 index 0000000000..4fa906686c --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.test.ts @@ -0,0 +1,152 @@ +/* + * 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 { InputError } from '@backstage/errors'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { createHandleAutocompleteRequest } from './autocomplete'; + +const mockGetClient = require('../util').getClient; + +jest.mock('../util', () => ({ + getClient: jest.fn(), +})); + +describe('handleAutocompleteRequest', () => { + const mockIntegrations = {} as ScmIntegrationRegistry; + const mockClient = { + Groups: { + all: jest.fn(), + allProjects: jest.fn(), + }, + Users: { + showCurrentUser: jest.fn(), + allProjects: jest.fn(), + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + mockGetClient.mockReturnValue(mockClient); + }); + + it('should return groups and current user', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + mockClient.Groups.all.mockResolvedValueOnce([ + { full_path: 'group1', id: 1 }, + { full_path: 'group2', id: 2 }, + ]); + mockClient.Groups.all.mockResolvedValueOnce([]); + mockClient.Users.showCurrentUser.mockResolvedValue({ + username: 'user1', + id: 3, + }); + + const result = await handleAutocompleteRequest({ + resource: 'groups', + token: 'token', + context: {}, + }); + + expect(result).toEqual({ + results: [ + { title: 'group1', id: '1' }, + { title: 'group2', id: '2' }, + { title: 'user1', id: '3' }, + ], + }); + }); + + it('should return repositories for a group', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + mockClient.Users.showCurrentUser.mockResolvedValue({ id: 3 }); + mockClient.Groups.allProjects.mockResolvedValue([ + { name: 'repo1', id: 1 }, + { name: 'repo2', id: 2 }, + ]); + + const result = await handleAutocompleteRequest({ + resource: 'repositories', + token: 'token', + context: { id: '1' }, + }); + + expect(result).toEqual({ + results: [ + { title: 'repo1', id: '1' }, + { title: 'repo2', id: '2' }, + ], + }); + }); + + it('should return repositories for a user', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + mockClient.Users.showCurrentUser.mockResolvedValue({ id: 1 }); + mockClient.Users.allProjects.mockResolvedValue([ + { name: 'repo1', id: 1 }, + { name: 'repo2', id: 2 }, + ]); + + const result = await handleAutocompleteRequest({ + resource: 'repositories', + token: 'token', + context: { id: '1' }, + }); + + expect(result).toEqual({ + results: [ + { title: 'repo1', id: '1' }, + { title: 'repo2', id: '2' }, + ], + }); + }); + + it('should throw an error for invalid resource', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + await expect( + handleAutocompleteRequest({ + resource: 'invalid', + token: 'token', + context: {}, + }), + ).rejects.toThrow(InputError); + }); + + it('should throw an error if context id is missing for repositories', async () => { + const handleAutocompleteRequest = createHandleAutocompleteRequest({ + integrations: mockIntegrations, + }); + + await expect( + handleAutocompleteRequest({ + resource: 'repositories', + token: 'token', + context: {}, + }), + ).rejects.toThrow(InputError); + }); +}); diff --git a/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.ts b/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.ts new file mode 100644 index 0000000000..6e9a7f79c4 --- /dev/null +++ b/plugins/scaffolder-backend-module-gitlab/src/autocomplete/autocomplete.ts @@ -0,0 +1,108 @@ +/* + * 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 { InputError } from '@backstage/errors'; +import { ScmIntegrationRegistry } from '@backstage/integration'; +import { getClient } from '../util'; + +export function createHandleAutocompleteRequest(options: { + integrations: ScmIntegrationRegistry; +}) { + return async function handleAutocompleteRequest({ + resource, + token, + context, + }: { + resource: string; + token: string; + context: Record; + }): Promise<{ + results: { + title?: string; + id: string; + }[]; + }> { + const { integrations } = options; + const client = getClient({ + host: context.host ?? 'gitlab.com', + integrations, + token, + }); + + switch (resource) { + case 'groups': { + let groups: any[] = []; + let page = 1; + const perPage = 100; + let response = []; + let continueFetch = true; + while (continueFetch) { + response = await client.Groups.all({ + pagination: 'offset', + page, + perPage, + }); + + groups = groups.concat(response); + if (response.length < perPage) continueFetch = false; + page++; + } + + const result: { + results: { + title: string; + id: string; + }[]; + } = { + results: groups.map(group => ({ + title: group.full_path, + id: group.id.toString(), + })), + }; + // append also user context + const user = await client.Users.showCurrentUser(); + result.results.push({ + title: user.username, + id: user.id.toString(), + }); + + return result; + } + case 'repositories': { + if (!context.id) + throw new InputError('Missing groupId and userId context parameter'); + + let response; + if ( + context.id === (await client.Users.showCurrentUser())?.id.toString() + ) { + response = await client.Users.allProjects(context.id); + } else { + response = await client.Groups.allProjects(context.id); + } + + return { + results: response.map(project => ({ + title: project.name.trim(), + id: project.id.toString(), + })), + }; + } + default: + throw new InputError(`Invalid resource: ${resource}`); + } + }; +} diff --git a/plugins/scaffolder-backend-module-gitlab/src/module.ts b/plugins/scaffolder-backend-module-gitlab/src/module.ts index 78175532ed..9f18532cdf 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/module.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/module.ts @@ -18,7 +18,10 @@ import { createBackendModule, } from '@backstage/backend-plugin-api'; import { ScmIntegrations } from '@backstage/integration'; -import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha'; +import { + scaffolderActionsExtensionPoint, + scaffolderAutocompleteExtensionPoint, +} from '@backstage/plugin-scaffolder-node/alpha'; import { createGitlabGroupEnsureExistsAction, createGitlabIssueAction, @@ -31,6 +34,7 @@ import { createTriggerGitlabPipelineAction, editGitlabIssueAction, } from './actions'; +import { createHandleAutocompleteRequest } from './autocomplete/autocomplete'; /** * @public @@ -43,9 +47,10 @@ export const gitlabModule = createBackendModule({ registerInit({ deps: { scaffolder: scaffolderActionsExtensionPoint, + autocomplete: scaffolderAutocompleteExtensionPoint, config: coreServices.rootConfig, }, - async init({ scaffolder, config }) { + async init({ scaffolder, autocomplete, config }) { const integrations = ScmIntegrations.fromConfig(config); scaffolder.addActions( @@ -60,6 +65,11 @@ export const gitlabModule = createBackendModule({ createPublishGitlabMergeRequestAction({ integrations }), createTriggerGitlabPipelineAction({ integrations }), ); + + autocomplete.addAutocompleteProvider({ + id: 'gitlab', + handler: createHandleAutocompleteRequest({ integrations }), + }); }, }); }, diff --git a/plugins/scaffolder-backend-module-gitlab/src/util.test.ts b/plugins/scaffolder-backend-module-gitlab/src/util.test.ts index 61c61e87c3..940dd30a05 100644 --- a/plugins/scaffolder-backend-module-gitlab/src/util.test.ts +++ b/plugins/scaffolder-backend-module-gitlab/src/util.test.ts @@ -62,7 +62,7 @@ describe('getTopLevelParentGroup', () => { parent_id: 0, path: '', description: '', - visibility: '', + visibility: 'public', share_with_group_lock: false, require_two_factor_authentication: false, two_factor_grace_period: 0, @@ -83,7 +83,7 @@ describe('getTopLevelParentGroup', () => { parent_id: 789, path: '', description: '', - visibility: '', + visibility: 'public', share_with_group_lock: false, require_two_factor_authentication: false, two_factor_grace_period: 0, @@ -104,7 +104,7 @@ describe('getTopLevelParentGroup', () => { parent_id: 456, path: '', description: '', - visibility: '', + visibility: 'public', share_with_group_lock: false, require_two_factor_authentication: false, two_factor_grace_period: 0, @@ -128,7 +128,7 @@ describe('getTopLevelParentGroup', () => { parent_id: 0, path: '', description: '', - visibility: '', + visibility: 'public', share_with_group_lock: false, require_two_factor_authentication: false, two_factor_grace_period: 0, diff --git a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md index e91ae18e3e..5a9e37810d 100644 --- a/plugins/scaffolder-backend-module-notifications/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-notifications/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-scaffolder-backend-module-notifications +## 0.1.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-notifications-node@0.2.10-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/plugin-notifications-common@0.0.7-next.0 + +## 0.1.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-notifications-node@0.2.10-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-notifications-common@0.0.6 + +## 0.1.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.10-next.0 + +## 0.1.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-notifications-common@0.0.6 + - @backstage/plugin-notifications-node@0.2.9 + - @backstage/plugin-scaffolder-node@0.6.0 + ## 0.1.3-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-notifications/package.json b/plugins/scaffolder-backend-module-notifications/package.json index fd0ed7fc48..c1ff7c6f0f 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.3-next.3", + "version": "0.1.5-next.2", "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 636b502953..dd877ba2dd 100644 --- a/plugins/scaffolder-backend-module-rails/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-rails/CHANGELOG.md @@ -1,5 +1,54 @@ # @backstage/plugin-scaffolder-backend-module-rails +## 0.5.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + +## 0.5.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + +## 0.5.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.5.2 + +### Patch Changes + +- 702f41d: Bumped dev dependencies `@types/node` +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.5.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-rails/package.json b/plugins/scaffolder-backend-module-rails/package.json index 5d465d8829..fe0046f17f 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.2-next.3", + "version": "0.5.4-next.2", "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 79eaa6cad8..9c30e449bb 100644 --- a/plugins/scaffolder-backend-module-sentry/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-sentry/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-scaffolder-backend-module-sentry +## 0.2.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/config@1.3.1-next.0 + +## 0.2.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + +## 0.2.2 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/errors@1.2.5 + ## 0.2.2-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-sentry/package.json b/plugins/scaffolder-backend-module-sentry/package.json index b9923b6b1d..27ace7cec6 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.2-next.3", + "version": "0.2.4-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", @@ -46,7 +46,6 @@ "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", - "node-fetch": "^2.7.0", "yaml": "^2.3.3" }, "devDependencies": { diff --git a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts index 686053b178..259b670f9e 100644 --- a/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts +++ b/plugins/scaffolder-backend-module-sentry/src/actions/createProject.ts @@ -17,7 +17,6 @@ import { createTemplateAction } from '@backstage/plugin-scaffolder-node'; import { InputError } from '@backstage/errors'; import { Config } from '@backstage/config'; -import fetch from 'node-fetch'; /** * Creates the `sentry:project:create` Scaffolder action. diff --git a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md index cd04321962..d09b9c097c 100644 --- a/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md +++ b/plugins/scaffolder-backend-module-yeoman/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-scaffolder-backend-module-yeoman +## 0.4.5-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.2 + - @backstage/types@1.2.0 + +## 0.4.5-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-scaffolder-node-test-utils@0.1.17-next.1 + - @backstage/types@1.2.0 + +## 0.4.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.16-next.0 + +## 0.4.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/plugin-scaffolder-node-test-utils@0.1.15 + ## 0.4.3-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend-module-yeoman/package.json b/plugins/scaffolder-backend-module-yeoman/package.json index f93a2991f2..7afce254e3 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.3-next.3", + "version": "0.4.5-next.2", "backstage": { "role": "backend-plugin-module", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-backend/CHANGELOG.md b/plugins/scaffolder-backend/CHANGELOG.md index 70dc12cdf4..c4e642e793 100644 --- a/plugins/scaffolder-backend/CHANGELOG.md +++ b/plugins/scaffolder-backend/CHANGELOG.md @@ -1,5 +1,158 @@ # @backstage/plugin-scaffolder-backend +## 1.28.0-next.2 + +### Patch Changes + +- dfc8b41: Updated dependency `@opentelemetry/api` to `^1.9.0`. +- 6c326cf: The --no-node-snapshot check needs to be done against process.execArgv instead of process.argv +- e913fdf: Add github backend module to create-app and improve error messages +- 0851834: Resolved an issue where the `templateManagementPermission` was not being exposed through the `/permissions/metadata` endpoint. +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-events-node@0.4.6-next.2 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.2 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.1 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## 1.28.0-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.5-next.1 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.4-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.1 + - @backstage/plugin-scaffolder-backend-module-github@0.5.4-next.1 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.4-next.1 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-events-node@0.4.6-next.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## 1.28.0-next.0 + +### Minor Changes + +- c05a343: Emit scaffolder events using the optional `EventsService` + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- 8f59dc5: Add fs:readdir to scaffolder startup +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-events-node@0.4.6-next.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.7.0-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.3-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.4-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-bitbucket-cloud-common@0.2.26-next.0 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.3-next.0 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.3-next.0 + - @backstage/plugin-scaffolder-backend-module-github@0.5.3-next.0 + +## 1.27.0 + +### Minor Changes + +- 0587633: Bumped the `isolated-vm` dependency from v4 to v5, which drops support for Node.js v16. +- e61d5ef: BREAKING EXPERIMENTAL: The `checkpoint` method now takes an object instead of previous arguments. + + ```ts + await ctx.checkpoint({ key: 'repo.create', fn: () => ockokit.repo.create({...})}) + ``` + + You can also now return `void` from the checkpoint if the method returns `void` inside the `checkpoint` handler. + +### Patch Changes + +- 6aa5b98: Fix tasks listing with postgres +- 59137ff: Fix issue with token not being available because it's now non-enumerable +- c5e39e7: Internal refactor to use the deferred from the types package +- e4f5d95: Align with type declaration of template filter/global function by supporting undefined as return value. +- d52d7f9: Support ISO and ms string forms of durations in config too +- 7ab3371: Modified `createDryRunner` and corresponding route to include `templateMetaData` inside the `templateInfo`. This allows custom action writers to access things like `templateInfo.entity.metadata.name` via the action context while executing templates using the dry run framework. +- 4e58bc7: Upgrade to uuid v11 internally +- 2dae341: Add new `fs:readdir` action to list current content of the workspace +- 97ba58f: Add example template for notification sending +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-backend-module-gitlab@0.6.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/plugin-bitbucket-cloud-common@0.2.25 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-server@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket-cloud@0.2.2 + - @backstage/plugin-scaffolder-node@0.6.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-catalog-backend-module-scaffolder-entity-model@0.2.2 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-scaffolder-backend-module-azure@0.2.2 + - @backstage/plugin-scaffolder-backend-module-bitbucket@0.3.2 + - @backstage/plugin-scaffolder-backend-module-gerrit@0.2.2 + - @backstage/plugin-scaffolder-backend-module-gitea@0.2.2 + - @backstage/plugin-scaffolder-backend-module-github@0.5.2 + ## 1.27.0-next.3 ### Patch Changes diff --git a/plugins/scaffolder-backend/config.d.ts b/plugins/scaffolder-backend/config.d.ts index f6b9522575..90040d68f1 100644 --- a/plugins/scaffolder-backend/config.d.ts +++ b/plugins/scaffolder-backend/config.d.ts @@ -26,6 +26,7 @@ export interface Config { name?: string; email?: string; }; + /** * The commit message used when new components are created. */ @@ -64,16 +65,15 @@ export interface Config { * be attempted to recover. * * If not specified, the default value is 5 seconds. - * */ - EXPERIMENTAL_recoverTasksTimeout?: HumanDuration; + EXPERIMENTAL_recoverTasksTimeout?: HumanDuration | string; /** * Makes sure to auto-expire and clean up things that time out or for other reasons should not be left lingering. * * By default, the frequency is every 5 minutes. */ - taskTimeoutJanitorFrequency?: HumanDuration; + taskTimeoutJanitorFrequency?: HumanDuration | string; /** * Sets the task's heartbeat timeout, when to consider a task to be staled. @@ -82,6 +82,6 @@ export interface Config { * * Default value is 24 hours. */ - taskTimeout?: HumanDuration; + taskTimeout?: HumanDuration | string; }; } diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 1b1ca25dee..beabffd2b0 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-backend", - "version": "1.27.0-next.3", + "version": "1.28.0-next.2", "description": "The Backstage backend plugin that helps you create new things", "backstage": { "role": "backend-plugin", @@ -73,6 +73,7 @@ "@backstage/plugin-bitbucket-cloud-common": "workspace:^", "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^", "@backstage/plugin-catalog-node": "workspace:^", + "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/plugin-permission-node": "workspace:^", "@backstage/plugin-scaffolder-backend-module-azure": "workspace:^", @@ -86,7 +87,7 @@ "@backstage/plugin-scaffolder-common": "workspace:^", "@backstage/plugin-scaffolder-node": "workspace:^", "@backstage/types": "workspace:^", - "@opentelemetry/api": "^1.3.0", + "@opentelemetry/api": "^1.9.0", "@types/express": "^4.17.6", "@types/luxon": "^3.0.0", "concat-stream": "^2.0.0", diff --git a/plugins/scaffolder-backend/report.api.md b/plugins/scaffolder-backend/report.api.md index cb5da51ea4..c2e6c18ad8 100644 --- a/plugins/scaffolder-backend/report.api.md +++ b/plugins/scaffolder-backend/report.api.md @@ -19,6 +19,7 @@ import { Config } from '@backstage/config'; import { DatabaseService } from '@backstage/backend-plugin-api'; import { DiscoveryService } from '@backstage/backend-plugin-api'; import { Duration } from 'luxon'; +import { EventsService } from '@backstage/plugin-events-node'; import { executeShellCommand as executeShellCommand_2 } from '@backstage/plugin-scaffolder-node'; import { ExecuteShellCommandOptions } from '@backstage/plugin-scaffolder-node'; import express from 'express'; @@ -520,6 +521,7 @@ export class DatabaseTaskStore implements TaskStore { // @public export type DatabaseTaskStoreOptions = { database: PluginDatabaseManager | Knex; + events?: EventsService; }; // @public @deprecated @@ -552,6 +554,8 @@ export interface RouterOptions { // (undocumented) discovery?: DiscoveryService; // (undocumented) + events?: EventsService; + // (undocumented) httpAuth?: HttpAuthService; // (undocumented) identity?: IdentityApi; diff --git a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile index 0c8b305de5..fb6f3a1f50 100644 --- a/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile +++ b/plugins/scaffolder-backend/scripts/Cookiecutter.dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20 +FROM alpine:3.21 RUN apk add --update \ git \ diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 17f7480a7d..1ee0634d45 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -15,8 +15,8 @@ */ import { - createBackendPlugin, coreServices, + createBackendPlugin, } from '@backstage/backend-plugin-api'; import { loggerToWinstonLogger } from '@backstage/backend-common'; import { ScmIntegrations } from '@backstage/integration'; @@ -47,9 +47,11 @@ import { createFetchTemplateFileAction, createFilesystemDeleteAction, createFilesystemRenameAction, + createFilesystemReadDirAction, createWaitAction, } from './scaffolder'; import { createRouter } from './service/router'; +import { eventsServiceRef } from '@backstage/plugin-events-node'; /** * Scaffolder plugin @@ -114,6 +116,7 @@ export const scaffolderPlugin = createBackendPlugin({ httpRouter: coreServices.httpRouter, httpAuth: coreServices.httpAuth, catalogClient: catalogServiceRef, + events: eventsServiceRef, }, async init({ logger, @@ -127,6 +130,7 @@ export const scaffolderPlugin = createBackendPlugin({ httpAuth, catalogClient, permissions, + events, }) { const log = loggerToWinstonLogger(logger); const integrations = ScmIntegrations.fromConfig(config); @@ -164,6 +168,7 @@ export const scaffolderPlugin = createBackendPlugin({ createCatalogWriteAction(), createFilesystemDeleteAction(), createFilesystemRenameAction(), + createFilesystemReadDirAction(), ]; const actionIds = actions.map(action => action.id).join(', '); @@ -189,6 +194,7 @@ export const scaffolderPlugin = createBackendPlugin({ permissions, autocompleteHandlers, additionalWorkspaceProviders, + events, }); httpRouter.use(router); }, diff --git a/plugins/scaffolder-backend/src/lib/templating/helpers.ts b/plugins/scaffolder-backend/src/lib/templating/helpers.ts index 3dfa4589bf..6c117543ff 100644 --- a/plugins/scaffolder-backend/src/lib/templating/helpers.ts +++ b/plugins/scaffolder-backend/src/lib/templating/helpers.ts @@ -17,7 +17,7 @@ export function isNoNodeSnapshotOptionProvided(): boolean { return ( process.env.NODE_OPTIONS?.includes('--no-node-snapshot') || - process.argv.includes('--no-node-snapshot') + process.execArgv.includes('--no-node-snapshot') ); } diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts index 3868380919..f00d7afad1 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/TemplateActionRegistry.ts @@ -37,7 +37,7 @@ export class TemplateActionRegistry { const action = this.actions.get(actionId); if (!action) { throw new NotFoundError( - `Template action with ID '${actionId}' is not registered.`, + `Template action with ID '${actionId}' is not registered. See https://backstage.io/docs/features/software-templates/builtin-actions/ on how to add a new action module.`, ); } return action; diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts index fbd314cbbc..eb0418b5ed 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.test.ts @@ -21,8 +21,9 @@ import { TaskSpec } from '@backstage/plugin-scaffolder-common'; import { ConflictError } from '@backstage/errors'; import { createMockDirectory } from '@backstage/backend-test-utils'; import fs from 'fs-extra'; +import { EventsService } from '@backstage/plugin-events-node'; -const createStore = async () => { +const createStore = async (events?: EventsService) => { const manager = DatabaseManager.fromConfig( new ConfigReader({ backend: { @@ -35,6 +36,7 @@ const createStore = async () => { ).forPlugin('scaffolder'); const store = await DatabaseTaskStore.create({ database: manager, + events, }); return { store, manager }; }; @@ -52,6 +54,14 @@ const workspaceDir = createMockDirectory({ }); describe('DatabaseTaskStore', () => { + const eventsService = { + publish: jest.fn(), + } as unknown as EventsService; + + beforeEach(() => { + jest.resetAllMocks(); + }); + it('should create the database store and run migration', async () => { const { store, manager } = await createStore(); expect(store).toBeDefined(); @@ -222,7 +232,7 @@ describe('DatabaseTaskStore', () => { }); it('should sent an event to start cancelling the task', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, @@ -244,10 +254,24 @@ describe('DatabaseTaskStore', () => { const event = events[0]; expect(event.taskId).toBe(taskId); expect(event.body.status).toBe('cancelled'); + + expect(eventsService.publish).toHaveBeenCalledWith({ + topic: 'scaffolder.task', + eventPayload: { + id: 1, + taskId, + status: 'cancelled', + body: { + message: `Step 2 has been cancelled.`, + stepId: 2, + status: 'cancelled', + }, + }, + }); }); it('should emit a log event', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, createdBy: 'me', @@ -310,7 +334,7 @@ describe('DatabaseTaskStore', () => { }); it('should complete the task', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, createdBy: 'me', @@ -327,10 +351,21 @@ describe('DatabaseTaskStore', () => { const taskAfterCompletion = await store.getTask(taskId); expect(taskAfterCompletion.status).toBe('cancelled'); + + expect(eventsService.publish).toHaveBeenCalledWith({ + topic: 'scaffolder.task', + eventPayload: { + id: taskId, + status: 'cancelled', + createdAt: expect.any(String), + lastHeartbeatAt: null, + createdBy: 'me', + }, + }); }); it('should claim a new task', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, createdBy: 'me', @@ -341,10 +376,22 @@ describe('DatabaseTaskStore', () => { const claimedTask = await store.getTask(taskId); expect(claimedTask.status).toBe('processing'); + + expect(eventsService.publish).toHaveBeenCalledWith({ + topic: 'scaffolder.task', + eventPayload: { + id: taskId, + status: 'processing', + createdAt: expect.any(String), + lastHeartbeatAt: null, + createdBy: 'me', + spec: {}, + }, + }); }); it('should restore the state of the task after the task recovery', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, createdBy: 'me', @@ -379,10 +426,22 @@ describe('DatabaseTaskStore', () => { const claimedTask = await store.getTask(taskId); expect(claimedTask.state).toEqual({ state: state.state }); + + expect(eventsService.publish).toHaveBeenCalledWith({ + topic: 'scaffolder.task', + eventPayload: { + id: 1, + taskId, + body: { + recoverStrategy: 'none', + }, + status: 'recovered', + }, + }); }); it('should shutdown the running task', async () => { - const { store } = await createStore(); + const { store } = await createStore(eventsService); const { taskId } = await store.createTask({ spec: {} as TaskSpec, createdBy: 'me', @@ -394,6 +453,17 @@ describe('DatabaseTaskStore', () => { const claimedTask = await store.getTask(taskId); expect(claimedTask.status).toBe('failed'); + + expect(eventsService.publish).toHaveBeenCalledWith({ + topic: 'scaffolder.task', + eventPayload: { + id: taskId, + status: 'failed', + createdAt: expect.any(String), + lastHeartbeatAt: expect.any(String), + createdBy: 'me', + }, + }); }); it('should be not possible to shutdown not running task', async () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts index 8913ec2675..8114532566 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/DatabaseTaskStore.ts @@ -45,6 +45,7 @@ import { serializeWorkspace, } from '@backstage/plugin-scaffolder-node/alpha'; import { flattenParams } from '../../service/helpers'; +import { EventsService } from '@backstage/plugin-events-node'; const migrationsDir = resolvePackagePath( '@backstage/plugin-scaffolder-backend', @@ -78,6 +79,7 @@ export type RawDbTaskEventRow = { */ export type DatabaseTaskStoreOptions = { database: PluginDatabaseManager | Knex; + events?: EventsService; }; /** @@ -112,6 +114,7 @@ const parseSqlDateToIsoString = (input: T): T | string => { */ export class DatabaseTaskStore implements TaskStore { private readonly db: Knex; + private readonly events?: EventsService; static async create( options: DatabaseTaskStoreOptions, @@ -121,7 +124,7 @@ export class DatabaseTaskStore implements TaskStore { await this.runMigrations(database, client); - return new DatabaseTaskStore(client); + return new DatabaseTaskStore(client, options.events); } private isRecoverableTask(spec: TaskSpec): boolean { @@ -177,8 +180,19 @@ export class DatabaseTaskStore implements TaskStore { } } - private constructor(client: Knex) { + private constructor(client: Knex, events?: EventsService) { this.db = client; + this.events = events; + } + + private getState(task: RawDbTaskRow) { + try { + return task.state ? JSON.parse(task.state).state : undefined; + } catch (error) { + throw new Error( + `Failed to parse state of the task '${task.id}', ${error}`, + ); + } } async list(options: { @@ -259,7 +273,7 @@ export class DatabaseTaskStore implements TaskStore { try { const spec = JSON.parse(result.spec); const secrets = result.secrets ? JSON.parse(result.secrets) : undefined; - const state = result.state ? JSON.parse(result.state).state : undefined; + const state = this.getState(result); return { id: result.id, spec, @@ -286,6 +300,17 @@ export class DatabaseTaskStore implements TaskStore { created_by: options.createdBy ?? null, status: 'open', }); + + this.events?.publish({ + topic: 'scaffolder.task', + eventPayload: { + id: taskId, + spec: options.spec, + createdBy: options.createdBy, + status: 'open', + }, + }); + return { taskId }; } @@ -317,27 +342,23 @@ export class DatabaseTaskStore implements TaskStore { return undefined; } - const getState = () => { - try { - return task.state ? JSON.parse(task.state).state : undefined; - } catch (error) { - throw new Error( - `Failed to parse state of the task '${task.id}', ${error}`, - ); - } - }; - - const secrets = this.parseTaskSecrets(task); - return { + const ret: SerializedTask = { id: task.id, spec, status: 'processing', lastHeartbeatAt: task.last_heartbeat_at, createdAt: task.created_at, createdBy: task.created_by ?? undefined, - secrets, - state: getState(), + state: this.getState(task), }; + + this.events?.publish({ + topic: 'scaffolder.task', + eventPayload: ret, + }); + + const secrets = this.parseTaskSecrets(task); + return { ...ret, secrets }; }); } @@ -408,11 +429,25 @@ export class DatabaseTaskStore implements TaskStore { ); } - await tx('task_events').insert({ - task_id: taskId, - event_type: 'completion', - body: JSON.stringify(eventBody), + this.events?.publish({ + topic: 'scaffolder.task', + eventPayload: { + id: taskId, + status: status, + lastHeartbeatAt: task.last_heartbeat_at, + createdAt: task.created_at, + createdBy: task.created_by, + state: this.getState(task), + }, }); + + await tx('task_events') + .insert({ + task_id: taskId, + event_type: 'completion', + body: JSON.stringify(eventBody), + }) + .returning('id'); }; if (status === 'cancelled') { @@ -448,11 +483,13 @@ export class DatabaseTaskStore implements TaskStore { ): Promise { const { taskId, body } = options; const serializedBody = JSON.stringify(body); - await this.db('task_events').insert({ - task_id: taskId, - event_type: 'log', - body: serializedBody, - }); + await this.db('task_events') + .insert({ + task_id: taskId, + event_type: 'log', + body: serializedBody, + }) + .returning('id'); } async getTaskState({ taskId }: { taskId: string }): Promise< @@ -596,10 +633,22 @@ export class DatabaseTaskStore implements TaskStore { ): Promise { const { taskId, body } = options; const serializedBody = JSON.stringify(body); - await this.db('task_events').insert({ - task_id: taskId, - event_type: 'cancelled', - body: serializedBody, + const [ret] = await this.db('task_events') + .insert({ + task_id: taskId, + event_type: 'cancelled', + body: serializedBody, + }) + .returning('id'); + + this.events?.publish({ + topic: 'scaffolder.task', + eventPayload: { + id: ret.id, + taskId, + status: 'cancelled', + body, + }, }); } @@ -665,13 +714,26 @@ export class DatabaseTaskStore implements TaskStore { for (const { id, spec } of result) { const taskSpec = JSON.parse(spec as string) as TaskSpec; - await tx('task_events').insert({ - task_id: id, - event_type: 'recovered', - body: JSON.stringify({ - recoverStrategy: - taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none', - }), + const event = { + recoverStrategy: + taskSpec.EXPERIMENTAL_recovery?.EXPERIMENTAL_strategy ?? 'none', + }; + const [ret] = await tx('task_events') + .insert({ + task_id: id, + event_type: 'recovered', + body: JSON.stringify(event), + }) + .returning('id'); + + this.events?.publish({ + topic: 'scaffolder.task', + eventPayload: { + id: ret.id, + taskId: id, + status: 'recovered', + body: event, + }, }); } }); diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts index 25caf7bad0..3990ac14b6 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.test.ts @@ -152,19 +152,37 @@ describe('NunjucksWorkflowRunner', () => { id: 'checkpoints-action', description: 'Mock action with checkpoints', handler: async ctx => { - const key1 = await ctx.checkpoint('key1', async () => { - return 'updated'; + const key1 = await ctx.checkpoint({ + key: 'key1', + fn: async () => 'updated', }); - const key2 = await ctx.checkpoint('key2', async () => { - return 'updated'; + const key2 = await ctx.checkpoint({ + key: 'key2', + fn: async () => 'updated', }); - const key3 = await ctx.checkpoint('key3', async () => { - return 'updated'; + const key3 = await ctx.checkpoint({ + key: 'key3', + fn: async () => 'updated', + }); + + const key4 = await ctx.checkpoint({ + key: 'key4', + fn: () => {}, + }); + + const key5 = await ctx.checkpoint({ + key: 'key5', + fn: async () => {}, }); ctx.output('key1', key1); ctx.output('key2', key2); ctx.output('key3', key3); + + // @ts-expect-error - this is void return + ctx.output('key4', key4); + // @ts-expect-error - this is void return + ctx.output('key5', key5); }, }); @@ -190,7 +208,7 @@ describe('NunjucksWorkflowRunner', () => { }); await expect(runner.execute(task)).rejects.toThrow( - "Template action with ID 'does-not-exist' is not registered.", + /Template action with ID 'does-not-exist' is not registered/, ); }); @@ -632,6 +650,9 @@ describe('NunjucksWorkflowRunner', () => { key1: '${{steps.test.output.key1}}', key2: '${{steps.test.output.key2}}', key3: '${{steps.test.output.key3}}', + key4: '${{steps.test.output.key4}}', + key5: '${{steps.test.output.key5}}', + key6: '${{steps.test.output.key6}}', }, }), getTaskState: (): Promise< @@ -661,6 +682,8 @@ describe('NunjucksWorkflowRunner', () => { expect(result.output.key1).toEqual('initial'); expect(result.output.key2).toEqual('updated'); expect(result.output.key3).toEqual('updated'); + expect(result.output.key4).toEqual(undefined); + expect(result.output.key5).toEqual(undefined); }); it('should template the output from simple actions', async () => { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 6f7551568f..c5413a08e0 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -364,6 +364,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { )}`, ); } + await action.handler({ input: iteration.input, secrets: task.secrets ?? {}, @@ -371,21 +372,25 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { logger: loggerToWinstonLogger(taskLogger), logStream: streamLogger, workspacePath, - async checkpoint( - keySuffix: string, - fn: () => Promise, - ) { - const key = `v1.task.checkpoint.${step.id}.${keySuffix}`; + async checkpoint(opts: { + key?: string; + fn: () => Promise | T; + }) { + const { key: checkpointKey, fn } = opts; + const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`; + try { - let prevValue: U | undefined; + let prevValue: T | undefined; + if (prevTaskState) { const prevState = ( prevTaskState.state?.checkpoints as { [key: string]: CheckpointState; } )?.[key]; + if (prevState && prevState.status === 'success') { - prevValue = prevState.value as U; + prevValue = prevState.value as T; } } @@ -395,7 +400,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { task.updateCheckpoint?.({ key, status: 'success', - value, + value: value ?? {}, }); } return value; diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index 715ada5de1..55d8b91293 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -51,6 +51,7 @@ import { import { AutocompleteHandler } from '@backstage/plugin-scaffolder-node/alpha'; import { UrlReaders } from '@backstage/backend-defaults/urlReader'; import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils'; +import { EventsService } from '@backstage/plugin-events-node'; const mockAccess = jest.fn(); @@ -99,6 +100,9 @@ describe('createRouter', () => { const auth = mockServices.auth(); const httpAuth = mockServices.httpAuth(); const discovery = mockServices.discovery(); + const events = { + publish: jest.fn(), + } as unknown as EventsService; const credentials = mockCredentials.user(); const token = mockCredentials.service.token({ @@ -211,6 +215,7 @@ describe('createRouter', () => { auth, httpAuth, discovery, + events, }); app = express().use(router); diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 261beb1f56..1758eb3fba 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -41,7 +41,7 @@ import { RESOURCE_TYPE_SCAFFOLDER_ACTION, RESOURCE_TYPE_SCAFFOLDER_TEMPLATE, scaffolderActionPermissions, - scaffolderTaskPermissions, + scaffolderPermissions, scaffolderTemplatePermissions, taskCancelPermission, taskCreatePermission, @@ -92,9 +92,9 @@ import { HttpAuthService, LifecycleService, PermissionsService, + resolveSafeChildPath, SchedulerService, UrlReaderService, - resolveSafeChildPath, } from '@backstage/backend-plugin-api'; import { IdentityApi, @@ -108,6 +108,7 @@ import { } from '@backstage/plugin-scaffolder-node/alpha'; import { pathToFileURL } from 'url'; import { v4 as uuid } from 'uuid'; +import { EventsService } from '@backstage/plugin-events-node'; /** * @@ -182,6 +183,7 @@ export interface RouterOptions { httpAuth?: HttpAuthService; identity?: IdentityApi; discovery?: DiscoveryService; + events?: EventsService; autocompleteHandlers?: Record; } @@ -294,6 +296,7 @@ export async function createRouter( discovery = HostDiscovery.fromConfig(config), identity = buildDefaultIdentityClient(options), autocompleteHandlers = {}, + events: eventsService, } = options; const { auth, httpAuth } = createLegacyAuthAdapters({ @@ -313,7 +316,10 @@ export async function createRouter( let taskBroker: TaskBroker; if (!options.taskBroker) { - const databaseTaskStore = await DatabaseTaskStore.create({ database }); + const databaseTaskStore = await DatabaseTaskStore.create({ + database, + events: eventsService, + }); taskBroker = new StorageTaskBroker( databaseTaskStore, logger, @@ -439,7 +445,7 @@ export async function createRouter( rules: actionRules, }, ], - permissions: scaffolderTaskPermissions, + permissions: scaffolderPermissions, }); router.use(permissionIntegrationRouter); @@ -475,6 +481,8 @@ export async function createRouter( description: schema.description, schema, })), + EXPERIMENTAL_formDecorators: + template.spec.EXPERIMENTAL_formDecorators, }); }, ) diff --git a/plugins/scaffolder-common/CHANGELOG.md b/plugins/scaffolder-common/CHANGELOG.md index 23250c50c6..183d67cc8c 100644 --- a/plugins/scaffolder-common/CHANGELOG.md +++ b/plugins/scaffolder-common/CHANGELOG.md @@ -1,5 +1,34 @@ # @backstage/plugin-scaffolder-common +## 1.5.8-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.5.8-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + +## 1.5.7 + +### Patch Changes + +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + ## 1.5.7-next.0 ### Patch Changes diff --git a/plugins/scaffolder-common/package.json b/plugins/scaffolder-common/package.json index 055fc6d336..34f8469776 100644 --- a/plugins/scaffolder-common/package.json +++ b/plugins/scaffolder-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-common", - "version": "1.5.7-next.0", + "version": "1.5.8-next.1", "description": "Common functionalities for the scaffolder, to be shared between scaffolder and scaffolder-backend plugin", "backstage": { "role": "common-library", diff --git a/plugins/scaffolder-common/report.api.md b/plugins/scaffolder-common/report.api.md index 8d7a61910d..3aa7e08121 100644 --- a/plugins/scaffolder-common/report.api.md +++ b/plugins/scaffolder-common/report.api.md @@ -77,6 +77,10 @@ export interface TemplateEntityV1beta3 extends Entity { type: string; presentation?: TemplatePresentationV1beta3; EXPERIMENTAL_recovery?: TemplateRecoveryV1beta3; + EXPERIMENTAL_formDecorators?: { + id: string; + input?: JsonObject; + }[]; parameters?: TemplateParametersV1beta3 | TemplateParametersV1beta3[]; steps: Array; output?: { diff --git a/plugins/scaffolder-common/src/Template.v1beta3.schema.json b/plugins/scaffolder-common/src/Template.v1beta3.schema.json index 4e34545d6d..58f8ef240a 100644 --- a/plugins/scaffolder-common/src/Template.v1beta3.schema.json +++ b/plugins/scaffolder-common/src/Template.v1beta3.schema.json @@ -173,6 +173,23 @@ } } }, + "EXPERIMENTAL_formDecorators": { + "type": "array", + "description": "A list of decorators and their inputs that the form should trigger before submitting the job", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The form hook ID" + }, + "input": { + "type": "object", + "description": "A object describing the inputs to the form hook." + } + } + } + }, "steps": { "type": "array", "description": "A list of steps to execute.", diff --git a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts index 0e2fec4264..c5b576b5c2 100644 --- a/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts +++ b/plugins/scaffolder-common/src/TemplateEntityV1beta3.ts @@ -56,6 +56,11 @@ export interface TemplateEntityV1beta3 extends Entity { */ EXPERIMENTAL_recovery?: TemplateRecoveryV1beta3; + /** + * Form hooks to be run + */ + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; + /** * This is a JSONSchema or an array of JSONSchema's which is used to render a form in the frontend * to collect user input and validate it against that schema. This can then be used in the `steps` part below to template diff --git a/plugins/scaffolder-node-test-utils/CHANGELOG.md b/plugins/scaffolder-node-test-utils/CHANGELOG.md index f1010e7654..6ba7bffacd 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.1.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.2.0-next.2 + - @backstage/plugin-scaffolder-node@0.6.2-next.2 + - @backstage/types@1.2.0 + +## 0.1.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-scaffolder-node@0.6.2-next.1 + - @backstage/backend-test-utils@1.2.0-next.1 + - @backstage/types@1.2.0 + +## 0.1.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-test-utils@1.2.0-next.0 + - @backstage/plugin-scaffolder-node@0.6.1-next.0 + - @backstage/types@1.2.0 + +## 0.1.15 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/backend-test-utils@1.1.0 + - @backstage/plugin-scaffolder-node@0.6.0 + ## 0.1.15-next.3 ### Patch Changes diff --git a/plugins/scaffolder-node-test-utils/package.json b/plugins/scaffolder-node-test-utils/package.json index 68fa0c1cfc..362c69ccb0 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.1.15-next.3", + "version": "0.1.17-next.2", "backstage": { "role": "node-library", "pluginId": "scaffolder", diff --git a/plugins/scaffolder-node/CHANGELOG.md b/plugins/scaffolder-node/CHANGELOG.md index 2a9a302738..327dbf0741 100644 --- a/plugins/scaffolder-node/CHANGELOG.md +++ b/plugins/scaffolder-node/CHANGELOG.md @@ -1,5 +1,65 @@ # @backstage/plugin-scaffolder-node +## 0.6.2-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## 0.6.2-next.1 + +### Patch Changes + +- 1a23421: Make sure that isomorphic git push commands are not proxied. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## 0.6.1-next.0 + +### Patch Changes + +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + +## 0.6.0 + +### Minor Changes + +- e61d5ef: BREAKING EXPERIMENTAL: The `checkpoint` method now takes an object instead of previous arguments. + + ```ts + await ctx.checkpoint({ key: 'repo.create', fn: () => ockokit.repo.create({...})}) + ``` + + You can also now return `void` from the checkpoint if the method returns `void` inside the `checkpoint` handler. + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + ## 0.5.1-next.3 ### Patch Changes diff --git a/plugins/scaffolder-node/package.json b/plugins/scaffolder-node/package.json index 8f3fbc3b0b..e8d52add6b 100644 --- a/plugins/scaffolder-node/package.json +++ b/plugins/scaffolder-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-node", - "version": "0.5.1-next.3", + "version": "0.6.2-next.2", "description": "The plugin-scaffolder-node module for @backstage/plugin-scaffolder-backend", "backstage": { "role": "node-library", diff --git a/plugins/scaffolder-node/report-alpha.api.md b/plugins/scaffolder-node/report-alpha.api.md index c9b8130f0e..eef9acc1c1 100644 --- a/plugins/scaffolder-node/report-alpha.api.md +++ b/plugins/scaffolder-node/report-alpha.api.md @@ -22,7 +22,8 @@ export type AutocompleteHandler = ({ context: Record; }) => Promise<{ results: { - title: string; + title?: string; + id: string; }[]; }>; diff --git a/plugins/scaffolder-node/report.api.md b/plugins/scaffolder-node/report.api.md index 6328f94bfd..c14a689d1a 100644 --- a/plugins/scaffolder-node/report.api.md +++ b/plugins/scaffolder-node/report.api.md @@ -31,10 +31,10 @@ export type ActionContext< secrets?: TaskSecrets; workspacePath: string; input: TActionInput; - checkpoint( - key: string, - fn: () => Promise, - ): Promise; + checkpoint(opts: { + key: string; + fn: () => Promise | T; + }): Promise; output( name: keyof TActionOutput, value: TActionOutput[keyof TActionOutput], diff --git a/plugins/scaffolder-node/src/actions/gitHelpers.test.ts b/plugins/scaffolder-node/src/actions/gitHelpers.test.ts index 7a61e592ec..664cc5c893 100644 --- a/plugins/scaffolder-node/src/actions/gitHelpers.test.ts +++ b/plugins/scaffolder-node/src/actions/gitHelpers.test.ts @@ -98,18 +98,11 @@ describe('initRepoAndPush', () => { }); }); - it('adds the appropriate remote', () => { - expect(mockedGit.addRemote).toHaveBeenCalledWith({ - dir: '/test/repo/dir/', - url: 'git@github.com:test/repo.git', - remote: 'origin', - }); - }); - it('pushes to the remote', () => { expect(mockedGit.push).toHaveBeenCalledWith({ dir: '/test/repo/dir/', remote: 'origin', + url: 'git@github.com:test/repo.git', }); }); }); diff --git a/plugins/scaffolder-node/src/actions/gitHelpers.ts b/plugins/scaffolder-node/src/actions/gitHelpers.ts index 9f2d5709a7..e24c0cf025 100644 --- a/plugins/scaffolder-node/src/actions/gitHelpers.ts +++ b/plugins/scaffolder-node/src/actions/gitHelpers.ts @@ -65,15 +65,11 @@ export async function initRepoAndPush(input: { author: authorInfo, committer: authorInfo, }); - await git.addRemote({ - dir, - url: remoteUrl, - remote: 'origin', - }); await git.push({ dir, remote: 'origin', + url: remoteUrl, }); return { commitHash }; diff --git a/plugins/scaffolder-node/src/actions/types.ts b/plugins/scaffolder-node/src/actions/types.ts index f0e4c12869..5dd9d5526f 100644 --- a/plugins/scaffolder-node/src/actions/types.ts +++ b/plugins/scaffolder-node/src/actions/types.ts @@ -38,10 +38,10 @@ export type ActionContext< secrets?: TaskSecrets; workspacePath: string; input: TActionInput; - checkpoint( - key: string, - fn: () => Promise, - ): Promise; + checkpoint(opts: { + key: string; + fn: () => Promise | T; + }): Promise; output( name: keyof TActionOutput, value: TActionOutput[keyof TActionOutput], diff --git a/plugins/scaffolder-node/src/alpha.ts b/plugins/scaffolder-node/src/alpha.ts index 6a0e34faf7..38a43d4865 100644 --- a/plugins/scaffolder-node/src/alpha.ts +++ b/plugins/scaffolder-node/src/alpha.ts @@ -16,10 +16,10 @@ import { createExtensionPoint } from '@backstage/backend-plugin-api'; import { + TaskBroker, TemplateAction, TemplateFilter, TemplateGlobal, - TaskBroker, } from '@backstage/plugin-scaffolder-node'; export * from './tasks/alpha'; @@ -95,7 +95,7 @@ export type AutocompleteHandler = ({ resource: string; token: string; context: Record; -}) => Promise<{ results: { title: string }[] }>; +}) => Promise<{ results: { title?: string; id: string }[] }>; /** * Extension point for adding autocomplete handler providers diff --git a/plugins/scaffolder-node/src/scm/git.test.ts b/plugins/scaffolder-node/src/scm/git.test.ts index 1c07dfb917..4a472a675a 100644 --- a/plugins/scaffolder-node/src/scm/git.test.ts +++ b/plugins/scaffolder-node/src/scm/git.test.ts @@ -452,6 +452,8 @@ describe('Git', () => { 'user-agent': 'git/@isomorphic-git', }, onAuth: expect.any(Function), + corsProxy: '', + url: undefined, }); }); @@ -480,6 +482,8 @@ describe('Git', () => { 'user-agent': 'git/@isomorphic-git', }, onAuth: expect.any(Function), + corsProxy: '', + url: undefined, }); }); @@ -506,6 +510,8 @@ describe('Git', () => { 'user-agent': 'git/@isomorphic-git', }, onAuth: expect.any(Function), + corsProxy: '', + url: undefined, }); }); diff --git a/plugins/scaffolder-node/src/scm/git.ts b/plugins/scaffolder-node/src/scm/git.ts index e7bad693fe..760be73114 100644 --- a/plugins/scaffolder-node/src/scm/git.ts +++ b/plugins/scaffolder-node/src/scm/git.ts @@ -262,9 +262,10 @@ export class Git { dir: string; remote: string; remoteRef?: string; + url?: string; force?: boolean; }) { - const { dir, remote, remoteRef, force } = options; + const { dir, remote, url, remoteRef, force } = options; this.config.logger?.info( `Pushing directory to remote {dir=${dir},remote=${remote}}`, ); @@ -278,7 +279,9 @@ export class Git { force, headers: this.headers, remote, + url, onAuth: this.onAuth, + corsProxy: '', }); } catch (ex) { this.config.logger?.error( diff --git a/plugins/scaffolder-react/CHANGELOG.md b/plugins/scaffolder-react/CHANGELOG.md index 84311f0f47..4efe1d95c8 100644 --- a/plugins/scaffolder-react/CHANGELOG.md +++ b/plugins/scaffolder-react/CHANGELOG.md @@ -1,5 +1,89 @@ # @backstage/plugin-scaffolder-react +## 1.14.2-next.2 + +### Patch Changes + +- 184161f: Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder. +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## 1.14.2-next.1 + +### Patch Changes + +- c846d76: Updated dependency `flatted` to `3.3.2`. +- b21a5ae: Open links in the scaffolder entity and step descriptions in a new tab, to ensure consistency and improve user experience +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## 1.14.2-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + +## 1.14.0 + +### Minor Changes + +- 69fb6e7: Fix `contextMenu` not being disabled bug in new scaffolder pages + +### Patch Changes + +- 8b5ff7e: Fix issue with form state not refreshing when updating +- ade301c: Fix issue with `Stepper` and trying to trim additional properties. This is now all behind `liveOmit` and `omitExtraData` instead. +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-permission-react@0.4.28 + ## 1.14.0-next.3 ### Minor Changes diff --git a/plugins/scaffolder-react/package.json b/plugins/scaffolder-react/package.json index 2c4a313bab..208fa93633 100644 --- a/plugins/scaffolder-react/package.json +++ b/plugins/scaffolder-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder-react", - "version": "1.14.0-next.3", + "version": "1.14.2-next.2", "description": "A frontend library that helps other Backstage plugins interact with the Scaffolder", "backstage": { "role": "web-library", @@ -73,14 +73,14 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.61", "@react-hookz/web": "^24.0.0", - "@rjsf/core": "5.21.2", - "@rjsf/material-ui": "5.21.2", - "@rjsf/utils": "5.21.2", - "@rjsf/validator-ajv8": "5.21.2", + "@rjsf/core": "5.23.1", + "@rjsf/material-ui": "5.23.1", + "@rjsf/utils": "5.23.1", + "@rjsf/validator-ajv8": "5.23.1", "@types/json-schema": "^7.0.9", "ajv-errors": "^3.0.0", "classnames": "^2.2.6", - "flatted": "3.3.1", + "flatted": "3.3.2", "humanize-duration": "^3.25.1", "json-schema": "^0.4.0", "json-schema-library": "^9.0.0", diff --git a/plugins/scaffolder-react/report-alpha.api.md b/plugins/scaffolder-react/report-alpha.api.md index 7084625ad4..4f9f86d1ac 100644 --- a/plugins/scaffolder-react/report-alpha.api.md +++ b/plugins/scaffolder-react/report-alpha.api.md @@ -5,12 +5,17 @@ ```ts /// +import { AnyApiFactory } from '@backstage/frontend-plugin-api'; +import { AnyApiRef } from '@backstage/core-plugin-api'; import { ApiHolder } from '@backstage/core-plugin-api'; +import { ApiRef } from '@backstage/frontend-plugin-api'; import { ComponentType } from 'react'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { CustomFieldValidator } from '@backstage/plugin-scaffolder-react'; import { Dispatch } from 'react'; import { ExtensionBlueprint } from '@backstage/frontend-plugin-api'; +import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; +import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { FieldExtensionComponentProps } from '@backstage/plugin-scaffolder-react'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FieldSchema } from '@backstage/plugin-scaffolder-react'; @@ -75,6 +80,39 @@ export function createFormField< TUiOptions extends z.ZodType, >(opts: FormFieldExtensionData): FormField; +// @alpha +export function createScaffolderFormDecorator< + TInputSchema extends { + [key in string]: (zImpl: typeof z) => z.ZodType; + } = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TDeps extends { + [key in string]: AnyApiRef; + } = { + [key in string]: AnyApiRef; + }, + TInput extends JsonObject = { + [key in keyof TInputSchema]: z.infer>; + }, +>(options: { + id: string; + schema?: { + input?: TInputSchema; + }; + deps?: TDeps; + decorator: ( + ctx: ScaffolderFormDecoratorContext, + deps: TDeps extends { + [key in string]: AnyApiRef; + } + ? { + [key in keyof TDeps]: TDeps[key]['T']; + } + : never, + ) => Promise; +}): ScaffolderFormDecorator; + // @alpha export const DefaultTemplateOutputs: (props: { output?: ScaffolderTaskOutput; @@ -137,6 +175,34 @@ export type FormFieldExtensionData< schema?: FieldSchema, z.output>; }; +// @alpha (undocumented) +export const formFieldsApi: ExtensionDefinition<{ + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef; + inputs: { + formFields: ExtensionInput< + ConfigurableExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >, + { + singleton: false; + optional: false; + } + >; + }; + kind: 'api'; + name: 'form-fields'; + params: { + factory: AnyApiFactory; + }; +}>; + +// @alpha (undocumented) +export const formFieldsApiRef: ApiRef; + // @alpha (undocumented) export type FormValidation = { [name: string]: FieldValidation | FormValidation; @@ -190,6 +256,33 @@ export interface ScaffolderFieldProps { required?: boolean; } +// @alpha (undocumented) +export type ScaffolderFormDecorator = { + readonly $$type: '@backstage/scaffolder/FormDecorator'; + readonly id: string; + readonly TInput: TInput; +}; + +// @alpha (undocumented) +export type ScaffolderFormDecoratorContext< + TInput extends JsonObject = JsonObject, +> = { + input: TInput; + formState: Record; + setFormState: ( + fn: (currentState: Record) => Record, + ) => void; + setSecrets: ( + fn: (currentState: Record) => Record, + ) => void; +}; + +// @alpha (undocumented) +export interface ScaffolderFormFieldsApi { + // (undocumented) + getFormFields(): Promise; +} + // @alpha (undocumented) export function ScaffolderPageContextMenu( props: ScaffolderPageContextMenuProps, @@ -346,9 +439,9 @@ export const useFormDataFromQuery: ( // @alpha (undocumented) export const useTemplateParameterSchema: (templateRef: string) => { - manifest: TemplateParameterSchema | undefined; + manifest?: TemplateParameterSchema | undefined; loading: boolean; - error: Error | undefined; + error?: Error | undefined; }; // @alpha diff --git a/plugins/scaffolder-react/report.api.md b/plugins/scaffolder-react/report.api.md index 5523b52ad9..8a6b4739a4 100644 --- a/plugins/scaffolder-react/report.api.md +++ b/plugins/scaffolder-react/report.api.md @@ -214,7 +214,8 @@ export interface ScaffolderApi { context?: Record; }): Promise<{ results: { - title: string; + title?: string; + id: string; }[]; }>; cancelTask(taskId: string): Promise; @@ -538,6 +539,10 @@ export type TemplateParameterSchema = { description?: string; schema: JsonObject; }>; + EXPERIMENTAL_formDecorators?: { + id: string; + input?: JsonObject; + }[]; }; // @public diff --git a/plugins/scaffolder-react/src/api/types.ts b/plugins/scaffolder-react/src/api/types.ts index bc37eed47e..8e4d989a55 100644 --- a/plugins/scaffolder-react/src/api/types.ts +++ b/plugins/scaffolder-react/src/api/types.ts @@ -245,5 +245,5 @@ export interface ScaffolderApi { provider: string; resource: string; context?: Record; - }): Promise<{ results: { title: string }[] }>; + }): Promise<{ results: { title?: string; id: string }[] }>; } diff --git a/plugins/scaffolder-react/src/extensions/index.tsx b/plugins/scaffolder-react/src/extensions/createScaffolderFieldExtension.tsx similarity index 100% rename from plugins/scaffolder-react/src/extensions/index.tsx rename to plugins/scaffolder-react/src/extensions/createScaffolderFieldExtension.tsx diff --git a/plugins/scaffolder-react/src/extensions/index.ts b/plugins/scaffolder-react/src/extensions/index.ts new file mode 100644 index 0000000000..874fa607fb --- /dev/null +++ b/plugins/scaffolder-react/src/extensions/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './createScaffolderFieldExtension'; diff --git a/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.test.tsx b/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.test.tsx new file mode 100644 index 0000000000..c21d43d6ff --- /dev/null +++ b/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.test.tsx @@ -0,0 +1,129 @@ +/* + * 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 React, { PropsWithChildren } from 'react'; +import { createPlugin } from '@backstage/core-plugin-api'; +import { TestApiProvider, wrapInTestApp } from '@backstage/test-utils'; +import { renderHook, waitFor } from '@testing-library/react'; +import { ScaffolderFormFieldsApi, formFieldsApiRef } from '../alpha'; +import { useCustomFieldExtensions } from './useCustomFieldExtensions'; +import { + ScaffolderFieldExtensions, + createScaffolderFieldExtension, +} from '../extensions'; + +const plugin = createPlugin({ + id: 'scaffolder', + apis: [], + routes: {}, + externalRoutes: {}, +}); + +describe('useCustomFieldExtensions', () => { + const mockFormFieldsApi: jest.Mocked = { + getFormFields: jest.fn(), + }; + const wrapper = ({ children }: PropsWithChildren<{}>) => + wrapInTestApp( + + {children} + , + ); + + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('should return field extensions from the React tree', async () => { + mockFormFieldsApi.getFormFields.mockResolvedValue([]); + const CustomFieldExtension = plugin.provide( + createScaffolderFieldExtension({ + name: 'test', + component: () =>
Test
, + }), + ); + + const { result } = renderHook( + () => + useCustomFieldExtensions( + + + , + ), + { + wrapper, + }, + ); + + expect(result.current).toEqual([expect.objectContaining({ name: 'test' })]); + }); + + it('should return field extensions from formFieldsApi', async () => { + mockFormFieldsApi.getFormFields.mockResolvedValue([ + { + name: 'blueprint', + component: () =>
Test
, + }, + ]); + + const { result } = renderHook(() => useCustomFieldExtensions(
), { + wrapper, + }); + + await waitFor(() => { + expect(result.current.length).toBeGreaterThan(0); + }); + + expect(result.current).toEqual([ + expect.objectContaining({ name: 'blueprint' }), + ]); + }); + + it('should return field extensions from both sources', async () => { + mockFormFieldsApi.getFormFields.mockResolvedValue([ + { + name: 'blueprint', + component: () =>
Test
, + }, + ]); + + const CustomFieldExtension = plugin.provide( + createScaffolderFieldExtension({ + name: 'test', + component: () =>
Test
, + }), + ); + + const { result } = renderHook( + () => + useCustomFieldExtensions( + + + , + ), + { + wrapper, + }, + ); + + await waitFor(() => { + expect(result.current).toHaveLength(2); + }); + + const fieldNames = result.current.map(field => field.name); + expect(fieldNames).toEqual(expect.arrayContaining(['test', 'blueprint'])); + }); +}); diff --git a/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.ts b/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.ts index 7e0aafd53f..d1e670330e 100644 --- a/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.ts +++ b/plugins/scaffolder-react/src/hooks/useCustomFieldExtensions.ts @@ -13,7 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { useElementFilter } from '@backstage/core-plugin-api'; +import { useAsync, useMountEffect } from '@react-hookz/web'; +import { useApi, useElementFilter } from '@backstage/core-plugin-api'; +import { formFieldsApiRef } from '../next'; import { FieldExtensionOptions } from '../extensions'; import { FIELD_EXTENSION_KEY, @@ -25,11 +27,21 @@ import { * @public */ export const useCustomFieldExtensions = < + // todo(blam): this shouldn't be here, should remove this, but this is a breaking change to remove the generic. TComponentDataType = FieldExtensionOptions, >( outlet: React.ReactNode, ) => { - return useElementFilter(outlet, elements => + // Get custom fields created with FormFieldBlueprint + const formFieldsApi = useApi(formFieldsApiRef); + const [{ result: blueprintFields }, methods] = useAsync( + formFieldsApi.getFormFields, + [], + ); + useMountEffect(methods.execute); + + // Get custom fields created with ScaffolderFieldExtensions + const outletFields = useElementFilter(outlet, elements => elements .selectByComponentData({ key: FIELD_EXTENSION_WRAPPER_KEY, @@ -38,4 +50,18 @@ export const useCustomFieldExtensions = < key: FIELD_EXTENSION_KEY, }), ); + + // This should really be a different type moving foward, but we do this to keep type compatibility. + // should probably also move the defaults into the API eventually too, but that will come with the move + // to the new frontend system. + const blueprintsToLegacy: FieldExtensionOptions[] = blueprintFields?.map( + field => ({ + component: field.component, + name: field.name, + validation: field.validation, + schema: field.schema?.schema, + }), + ); + + return [...blueprintsToLegacy, ...outletFields] as TComponentDataType[]; }; diff --git a/plugins/scaffolder/src/alpha/api/FormFieldsApi.ts b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts similarity index 95% rename from plugins/scaffolder/src/alpha/api/FormFieldsApi.ts rename to plugins/scaffolder-react/src/next/api/FormFieldsApi.ts index 35141463d5..7712b91a18 100644 --- a/plugins/scaffolder/src/alpha/api/FormFieldsApi.ts +++ b/plugins/scaffolder-react/src/next/api/FormFieldsApi.ts @@ -21,7 +21,7 @@ import { } from '@backstage/frontend-plugin-api'; import { formFieldsApiRef } from './ref'; import { ScaffolderFormFieldsApi } from './types'; -import { FormFieldBlueprint } from '@backstage/plugin-scaffolder-react/alpha'; +import { FormFieldBlueprint } from '../blueprints'; import { FormField, OpaqueFormField } from '@internal/scaffolder'; class DefaultScaffolderFormFieldsApi implements ScaffolderFormFieldsApi { @@ -40,6 +40,7 @@ class DefaultScaffolderFormFieldsApi implements ScaffolderFormFieldsApi { } } +/** @alpha */ export const formFieldsApi = ApiBlueprint.makeWithOverrides({ name: 'form-fields', inputs: { diff --git a/plugins/scaffolder-react/src/next/api/index.ts b/plugins/scaffolder-react/src/next/api/index.ts new file mode 100644 index 0000000000..ecc62e5acf --- /dev/null +++ b/plugins/scaffolder-react/src/next/api/index.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +export { formFieldsApi } from './FormFieldsApi'; +export { formFieldsApiRef } from './ref'; +export type { ScaffolderFormFieldsApi } from './types'; diff --git a/plugins/scaffolder-react/src/next/api/ref.ts b/plugins/scaffolder-react/src/next/api/ref.ts new file mode 100644 index 0000000000..eaa6f49c21 --- /dev/null +++ b/plugins/scaffolder-react/src/next/api/ref.ts @@ -0,0 +1,23 @@ +/* + * 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 { createApiRef } from '@backstage/frontend-plugin-api'; +import { ScaffolderFormFieldsApi } from './types'; + +/** @alpha */ +export const formFieldsApiRef = createApiRef({ + id: 'plugin.scaffolder.form-fields', +}); diff --git a/plugins/scaffolder-react/src/next/api/types.ts b/plugins/scaffolder-react/src/next/api/types.ts new file mode 100644 index 0000000000..2c98111b1c --- /dev/null +++ b/plugins/scaffolder-react/src/next/api/types.ts @@ -0,0 +1,22 @@ +/* + * 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 { FormFieldExtensionData } from '../blueprints'; + +/** @alpha */ +export interface ScaffolderFormFieldsApi { + getFormFields(): Promise; +} diff --git a/plugins/scaffolder-react/src/next/components/Form/DescriptionFieldTemplate.tsx b/plugins/scaffolder-react/src/next/components/Form/DescriptionFieldTemplate.tsx index 7731cac3f8..5f12e0f1a3 100644 --- a/plugins/scaffolder-react/src/next/components/Form/DescriptionFieldTemplate.tsx +++ b/plugins/scaffolder-react/src/next/components/Form/DescriptionFieldTemplate.tsx @@ -56,6 +56,7 @@ export const DescriptionFieldTemplate = < return ( ); diff --git a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx index 9afc18c438..31f5ac2881 100644 --- a/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx +++ b/plugins/scaffolder-react/src/next/components/Workflow/Workflow.tsx @@ -121,6 +121,7 @@ export const Workflow = (workflowProps: WorkflowProps): JSX.Element | null => { subheader={ { + it('should return a decorator', () => { + const decorator = createScaffolderFormDecorator({ + id: 'test', + deps: {}, + decorator: async () => {}, + }); + + expect(decorator).toMatchInlineSnapshot(` + { + "$$type": "@backstage/scaffolder/FormDecorator", + "TInput": null, + "decorator": [Function], + "deps": {}, + "id": "test", + "version": "v1", + } + `); + }); + + it('should allow passing schema and be typesafe', () => { + const decorator = createScaffolderFormDecorator({ + id: 'test', + deps: {}, + schema: { + input: { + name: z => z.string(), + age: z => z.number(), + }, + }, + decorator: async ctx => { + const name: string = ctx.input.name; + + // @ts-expect-error + const number: string = ctx.input.age; + + expect([name, number]).toBeDefined(); + }, + }); + + expect(decorator).toMatchInlineSnapshot(` + { + "$$type": "@backstage/scaffolder/FormDecorator", + "TInput": null, + "decorator": [Function], + "deps": {}, + "id": "test", + "schema": { + "input": { + "age": [Function], + "name": [Function], + }, + }, + "version": "v1", + } + `); + }); +}); diff --git a/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts new file mode 100644 index 0000000000..0064ae0397 --- /dev/null +++ b/plugins/scaffolder-react/src/next/extensions/createScaffolderFormDecorator.ts @@ -0,0 +1,84 @@ +/* + * 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 { AnyApiRef } from '@backstage/core-plugin-api'; +import { JsonObject, JsonValue } from '@backstage/types'; +import { OpaqueFormDecorator } from '@internal/scaffolder'; +import { z } from 'zod'; + +/** @alpha */ +export type ScaffolderFormDecoratorContext< + TInput extends JsonObject = JsonObject, +> = { + input: TInput; + formState: Record; + + setFormState: ( + fn: (currentState: Record) => Record, + ) => void; + setSecrets: ( + fn: (currentState: Record) => Record, + ) => void; +}; + +/** @alpha */ +export type ScaffolderFormDecorator = { + readonly $$type: '@backstage/scaffolder/FormDecorator'; + readonly id: string; + readonly TInput: TInput; +}; + +/** + * Method for creating decorators which can be used to collect + * secrets from the user before submitting to the backend. + * @alpha + */ +export function createScaffolderFormDecorator< + TInputSchema extends { [key in string]: (zImpl: typeof z) => z.ZodType } = { + [key in string]: (zImpl: typeof z) => z.ZodType; + }, + TDeps extends { [key in string]: AnyApiRef } = { [key in string]: AnyApiRef }, + TInput extends JsonObject = { + [key in keyof TInputSchema]: z.infer>; + }, +>(options: { + id: string; + schema?: { + input?: TInputSchema; + }; + deps?: TDeps; + decorator: ( + ctx: ScaffolderFormDecoratorContext, + deps: TDeps extends { [key in string]: AnyApiRef } + ? { [key in keyof TDeps]: TDeps[key]['T'] } + : never, + ) => Promise; +}): ScaffolderFormDecorator { + return OpaqueFormDecorator.createInstance('v1', { + ...options, + TInput: null as unknown as TInput, + } as { + id: string; + schema?: { + input?: TInputSchema; + }; + TInput: TInput; + deps?: TDeps; + decorator: ( + ctx: ScaffolderFormDecoratorContext, + deps: { [key in string]: AnyApiRef['T'] }, + ) => Promise; + }); +} diff --git a/plugins/scaffolder-react/src/next/extensions/index.ts b/plugins/scaffolder-react/src/next/extensions/index.ts new file mode 100644 index 0000000000..73bfa749f6 --- /dev/null +++ b/plugins/scaffolder-react/src/next/extensions/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './createScaffolderFormDecorator'; diff --git a/plugins/scaffolder-react/src/next/hooks/useTemplateParameterSchema.ts b/plugins/scaffolder-react/src/next/hooks/useTemplateParameterSchema.ts index 4b4f21ae71..452e3a67a8 100644 --- a/plugins/scaffolder-react/src/next/hooks/useTemplateParameterSchema.ts +++ b/plugins/scaffolder-react/src/next/hooks/useTemplateParameterSchema.ts @@ -22,15 +22,21 @@ import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; /** * @alpha */ -export const useTemplateParameterSchema = (templateRef: string) => { +export const useTemplateParameterSchema = ( + templateRef: string, +): { manifest?: TemplateParameterSchema; loading: boolean; error?: Error } => { const scaffolderApi = useApi(scaffolderApiRef); - const { value, loading, error } = useAsync( + const { + value: manifest, + loading, + error, + } = useAsync( () => scaffolderApi.getTemplateParameterSchema(templateRef), [scaffolderApi, templateRef], ); return { - manifest: value as TemplateParameterSchema | undefined, + manifest, loading, error, }; diff --git a/plugins/scaffolder-react/src/next/index.ts b/plugins/scaffolder-react/src/next/index.ts index 07f4565166..9c967a5db9 100644 --- a/plugins/scaffolder-react/src/next/index.ts +++ b/plugins/scaffolder-react/src/next/index.ts @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +export * from './api'; export * from './components'; export * from './lib'; export * from './hooks'; export * from './overridableComponents'; export * from './blueprints'; +export * from './extensions'; diff --git a/plugins/scaffolder-react/src/types.ts b/plugins/scaffolder-react/src/types.ts index c1c26f32bb..5f557198c6 100644 --- a/plugins/scaffolder-react/src/types.ts +++ b/plugins/scaffolder-react/src/types.ts @@ -33,4 +33,5 @@ export type TemplateParameterSchema = { description?: string; schema: JsonObject; }>; + EXPERIMENTAL_formDecorators?: { id: string; input?: JsonObject }[]; }; diff --git a/plugins/scaffolder/CHANGELOG.md b/plugins/scaffolder/CHANGELOG.md index 7974a03783..98f1eb2f0b 100644 --- a/plugins/scaffolder/CHANGELOG.md +++ b/plugins/scaffolder/CHANGELOG.md @@ -1,5 +1,104 @@ # @backstage/plugin-scaffolder +## 1.27.2-next.2 + +### Patch Changes + +- 184161f: Scaffolder field extensions registered with `FormFieldBlueprint` are now collected in the `useCustomFieldExtensions` hook, enabling them for use in the scaffolder. +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/plugin-scaffolder-react@1.14.2-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-react@0.4.29-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.1 + +## 1.27.2-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-scaffolder-react@1.14.2-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + +## 1.27.2-next.0 + +### Patch Changes + +- 3c62a50: Experimental support for `formDecorators` to enable secret collection and mutations to the parameters for scaffolder tasks +- c4ffd13: Added the autocomplete feature to GitlabRepoUrlPicker +- 9951ba4: Updated dependency `@rjsf/utils` to `5.23.1`. + Updated dependency `@rjsf/core` to `5.23.1`. + Updated dependency `@rjsf/material-ui` to `5.23.1`. + Updated dependency `@rjsf/validator-ajv8` to `5.23.1`. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-scaffolder-common@1.5.8-next.0 + - @backstage/plugin-scaffolder-react@1.14.2-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + +## 1.27.0 + +### Minor Changes + +- f61d4cc: Add scaffolder permission `scaffolder.template.management` for accessing the template management features +- 69fb6e7: Fix `contextMenu` not being disabled bug in new scaffolder pages + +### Patch Changes + +- 99471cd: fix(scaffolder): use `onInputChange` in `RepoUrlPicker` to fix issue with the value not updating properly +- 8e4bed4: Updated dependency `idb-keyval` to `5.1.5`. +- 7669af3: Revert the change of the option label for `EntityPicker` +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/types@1.2.0 + - @backstage/plugin-scaffolder-react@1.14.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/plugin-scaffolder-common@1.5.7 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-react@0.4.28 + ## 1.27.0-next.3 ### Minor Changes diff --git a/plugins/scaffolder/package.json b/plugins/scaffolder/package.json index 2fbfc33d26..96f189506d 100644 --- a/plugins/scaffolder/package.json +++ b/plugins/scaffolder/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-scaffolder", - "version": "1.27.0-next.3", + "version": "1.27.2-next.2", "description": "The Backstage plugin that helps you create new things", "backstage": { "role": "frontend-plugin", @@ -81,10 +81,10 @@ "@material-ui/lab": "4.0.0-alpha.61", "@microsoft/fetch-event-source": "^2.0.1", "@react-hookz/web": "^24.0.0", - "@rjsf/core": "5.21.2", - "@rjsf/material-ui": "5.21.2", - "@rjsf/utils": "5.21.2", - "@rjsf/validator-ajv8": "5.21.2", + "@rjsf/core": "5.23.1", + "@rjsf/material-ui": "5.23.1", + "@rjsf/utils": "5.23.1", + "@rjsf/validator-ajv8": "5.23.1", "@uiw/react-codemirror": "^4.9.3", "classnames": "^2.2.6", "git-url-parse": "^15.0.0", diff --git a/plugins/scaffolder/report-alpha.api.md b/plugins/scaffolder/report-alpha.api.md index 4253b2b914..e272b57655 100644 --- a/plugins/scaffolder/report-alpha.api.md +++ b/plugins/scaffolder/report-alpha.api.md @@ -7,12 +7,14 @@ import { AnyApiFactory } from '@backstage/frontend-plugin-api'; import { AnyRouteRefParams } from '@backstage/frontend-plugin-api'; +import { ApiRef } from '@backstage/frontend-plugin-api'; import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api'; import { ExtensionDefinition } from '@backstage/frontend-plugin-api'; import { ExtensionInput } from '@backstage/frontend-plugin-api'; import { ExternalRouteRef } from '@backstage/frontend-plugin-api'; import { FieldExtensionOptions } from '@backstage/plugin-scaffolder-react'; import { FormField } from '@internal/scaffolder'; +import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; import type { FormProps as FormProps_2 } from '@rjsf/core'; import { FormProps as FormProps_3 } from '@backstage/plugin-scaffolder-react'; import { FrontendPlugin } from '@backstage/frontend-plugin-api'; @@ -23,6 +25,8 @@ import { PathParams } from '@backstage/core-plugin-api'; import { default as React_2 } from 'react'; import { ReviewStepProps } from '@backstage/plugin-scaffolder-react'; import { RouteRef } from '@backstage/frontend-plugin-api'; +import { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; +import { ScaffolderFormFieldsApi } from '@backstage/plugin-scaffolder-react/alpha'; import { SubRouteRef } from '@backstage/frontend-plugin-api'; import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common'; import { TemplateGroupFilter } from '@backstage/plugin-scaffolder-react'; @@ -49,9 +53,7 @@ const _default: FrontendPlugin< }>; }, { - 'api:scaffolder': ExtensionDefinition<{ - kind: 'api'; - name: undefined; + 'api:scaffolder/form-fields': ExtensionDefinition<{ config: {}; configInput: {}; output: ConfigurableExtensionDataRef< @@ -59,7 +61,21 @@ const _default: FrontendPlugin< 'core.api.factory', {} >; - inputs: {}; + inputs: { + formFields: ExtensionInput< + ConfigurableExtensionDataRef< + () => Promise, + 'scaffolder.form-field-loader', + {} + >, + { + singleton: false; + optional: false; + } + >; + }; + kind: 'api'; + name: 'form-fields'; params: { factory: AnyApiFactory; }; @@ -126,7 +142,9 @@ const _default: FrontendPlugin< field: () => Promise; }; }>; - 'api:scaffolder/form-fields': ExtensionDefinition<{ + 'api:scaffolder': ExtensionDefinition<{ + kind: 'api'; + name: undefined; config: {}; configInput: {}; output: ConfigurableExtensionDataRef< @@ -134,21 +152,7 @@ const _default: FrontendPlugin< 'core.api.factory', {} >; - inputs: { - formFields: ExtensionInput< - ConfigurableExtensionDataRef< - () => Promise, - 'scaffolder.form-field-loader', - {} - >, - { - singleton: false; - optional: false; - } - >; - }; - kind: 'api'; - name: 'form-fields'; + inputs: {}; params: { factory: AnyApiFactory; }; @@ -157,6 +161,23 @@ const _default: FrontendPlugin< >; export default _default; +// @alpha (undocumented) +export class DefaultScaffolderFormDecoratorsApi + implements ScaffolderFormDecoratorsApi +{ + // (undocumented) + static create(options?: { + decorators: ScaffolderFormDecorator[]; + }): DefaultScaffolderFormDecoratorsApi; + // (undocumented) + getFormDecorators(): Promise; +} + +// @alpha (undocumented) +export const formDecoratorsApiRef: ApiRef; + +export { formFieldsApiRef }; + // @alpha @deprecated export type FormProps = Pick< FormProps_2, @@ -170,6 +191,14 @@ export type ScaffolderCustomFieldExplorerClassKey = | 'fieldForm' | 'preview'; +// @alpha (undocumented) +export interface ScaffolderFormDecoratorsApi { + // (undocumented) + getFormDecorators(): Promise; +} + +export { ScaffolderFormFieldsApi }; + // @public (undocumented) export type ScaffolderTemplateEditorClassKey = | 'root' diff --git a/plugins/scaffolder/report.api.md b/plugins/scaffolder/report.api.md index 538b2cd9eb..453b482ce2 100644 --- a/plugins/scaffolder/report.api.md +++ b/plugins/scaffolder/report.api.md @@ -531,7 +531,8 @@ export class ScaffolderClient implements ScaffolderApi_2 { context?: Record; }): Promise<{ results: { - title: string; + title?: string; + id: string; }[]; }>; // (undocumented) diff --git a/plugins/scaffolder/src/alpha/api.tsx b/plugins/scaffolder/src/alpha/api.tsx deleted file mode 100644 index 06364cd6e9..0000000000 --- a/plugins/scaffolder/src/alpha/api.tsx +++ /dev/null @@ -1,46 +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 { - ApiBlueprint, - createApiFactory, - discoveryApiRef, - fetchApiRef, - identityApiRef, -} from '@backstage/frontend-plugin-api'; -import { scmIntegrationsApiRef } from '@backstage/integration-react'; -import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; -import { ScaffolderClient } from '../api'; - -export const scaffolderApi = ApiBlueprint.make({ - params: { - factory: createApiFactory({ - api: scaffolderApiRef, - deps: { - discoveryApi: discoveryApiRef, - scmIntegrationsApi: scmIntegrationsApiRef, - fetchApi: fetchApiRef, - identityApi: identityApiRef, - }, - factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => - new ScaffolderClient({ - discoveryApi, - scmIntegrationsApi, - fetchApi, - identityApi, - }), - }), - }, -}); diff --git a/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts new file mode 100644 index 0000000000..13c4b6d1a2 --- /dev/null +++ b/plugins/scaffolder/src/alpha/api/FormDecoratorsApi.ts @@ -0,0 +1,39 @@ +/* + * 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 { ScaffolderFormDecoratorsApi } from './types'; +import { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; + +/** @alpha */ +export class DefaultScaffolderFormDecoratorsApi + implements ScaffolderFormDecoratorsApi +{ + private constructor( + private readonly options: { + decorators: Array; + }, + ) {} + + static create(options?: { decorators: ScaffolderFormDecorator[] }) { + return new DefaultScaffolderFormDecoratorsApi( + options ?? { decorators: [] }, + ); + } + + async getFormDecorators(): Promise { + return this.options.decorators; + } +} diff --git a/plugins/scaffolder/src/alpha/api/index.ts b/plugins/scaffolder/src/alpha/api/index.ts index bbc30ef50b..07d4b65a3b 100644 --- a/plugins/scaffolder/src/alpha/api/index.ts +++ b/plugins/scaffolder/src/alpha/api/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ -export { formFieldsApiRef } from './ref'; -export type { ScaffolderFormFieldsApi } from './types'; +export { formDecoratorsApiRef } from './ref'; +export type { ScaffolderFormDecoratorsApi } from './types'; +export { DefaultScaffolderFormDecoratorsApi } from './FormDecoratorsApi'; diff --git a/plugins/scaffolder/src/alpha/api/ref.ts b/plugins/scaffolder/src/alpha/api/ref.ts index 52bc44e674..532669d0ad 100644 --- a/plugins/scaffolder/src/alpha/api/ref.ts +++ b/plugins/scaffolder/src/alpha/api/ref.ts @@ -15,8 +15,9 @@ */ import { createApiRef } from '@backstage/frontend-plugin-api'; -import { ScaffolderFormFieldsApi } from './types'; +import { ScaffolderFormDecoratorsApi } from './types'; -export const formFieldsApiRef = createApiRef({ - id: 'plugin.scaffolder.form-fields', +/** @alpha */ +export const formDecoratorsApiRef = createApiRef({ + id: 'plugin.scaffolder.form-decorators', }); diff --git a/plugins/scaffolder/src/alpha/api/types.ts b/plugins/scaffolder/src/alpha/api/types.ts index 81f08b18e2..1d2d331adf 100644 --- a/plugins/scaffolder/src/alpha/api/types.ts +++ b/plugins/scaffolder/src/alpha/api/types.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import { FormFieldExtensionData } from '@backstage/plugin-scaffolder-react/alpha'; +import { ScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; -export interface ScaffolderFormFieldsApi { - getFormFields(): Promise; +/** @alpha */ +export interface ScaffolderFormDecoratorsApi { + getFormDecorators(): Promise; } diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx index 18211d185a..7d978e5c38 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.test.tsx @@ -33,6 +33,8 @@ import { rootRouteRef } from '../../../routes'; import { ANNOTATION_EDIT_URL } from '@backstage/catalog-model'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; +import { ScaffolderFormDecoratorsApi } from '../../api/types'; +import { formDecoratorsApiRef } from '../../api/ref'; jest.mock('react-router-dom', () => { return { @@ -55,11 +57,16 @@ const scaffolderApiMock: jest.Mocked = { autocomplete: jest.fn(), }; +const scaffolderDecoratorsMock: jest.Mocked = { + getFormDecorators: jest.fn().mockResolvedValue([]), +}; + const catalogApi = catalogApiMock.mock(); const analyticsApi = mockApis.analytics(); const apis = TestApiRegistry.from( [scaffolderApiRef, scaffolderApiMock], + [formDecoratorsApiRef, scaffolderDecoratorsMock], [catalogApiRef, catalogApi], [analyticsApiRef, analyticsApi], [catalogApiRef, catalogApi], diff --git a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx index b5e24a7d52..2ed6de4479 100644 --- a/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx +++ b/plugins/scaffolder/src/alpha/components/TemplateWizardPage/TemplateWizardPage.tsx @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import React, { useState } from 'react'; import { Navigate, useNavigate } from 'react-router-dom'; import useAsync from 'react-use/esm/useAsync'; import { @@ -36,9 +36,12 @@ import { } from '@backstage/plugin-scaffolder-react'; import { catalogApiRef } from '@backstage/plugin-catalog-react'; -import { Workflow } from '@backstage/plugin-scaffolder-react/alpha'; +import { + Workflow, + useTemplateParameterSchema, +} from '@backstage/plugin-scaffolder-react/alpha'; import { JsonValue } from '@backstage/types'; -import { Header, Page } from '@backstage/core-components'; +import { Header, Page, Progress } from '@backstage/core-components'; import { rootRouteRef, @@ -49,6 +52,7 @@ import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { scaffolderTranslationRef } from '../../../translation'; import { TemplateWizardPageContextMenu } from './TemplateWizardPageContextMenu'; +import { useFormDecorators } from '../../hooks'; /** * @alpha @@ -70,9 +74,10 @@ export type TemplateWizardPageProps = { export const TemplateWizardPage = (props: TemplateWizardPageProps) => { const rootRef = useRouteRef(rootRouteRef); const taskRoute = useRouteRef(scaffolderTaskRouteRef); - const { secrets } = useTemplateSecrets(); + const { secrets: contextSecrets } = useTemplateSecrets(); const scaffolderApi = useApi(scaffolderApiRef); const catalogApi = useApi(catalogApiRef); + const [isCreating, setIsCreating] = useState(false); const navigate = useNavigate(); const { templateName, namespace } = useRouteRefParams( selectedTemplateRouteRef, @@ -85,12 +90,26 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { name: templateName, }); + const { manifest } = useTemplateParameterSchema(templateRef); + const decorators = useFormDecorators({ manifest }); + const { value: editUrl } = useAsync(async () => { const data = await catalogApi.getEntityByRef(templateRef); return data?.metadata.annotations?.[ANNOTATION_EDIT_URL]; }, [templateRef, catalogApi]); - const onCreate = async (values: Record) => { + const onCreate = async (initialValues: Record) => { + if (isCreating) { + return; + } + + setIsCreating(true); + + const { formState: values, secrets } = await decorators.run({ + formState: initialValues, + secrets: contextSecrets, + }); + const { taskId } = await scaffolderApi.scaffold({ templateRef, values, @@ -113,6 +132,7 @@ export const TemplateWizardPage = (props: TemplateWizardPageProps) => { > + {isCreating && } import('./fields/RepoUrlPicker').then(m => m.RepoUrlPicker), }, }); + +export const scaffolderApi = ApiBlueprint.make({ + params: { + factory: createApiFactory({ + api: scaffolderApiRef, + deps: { + discoveryApi: discoveryApiRef, + scmIntegrationsApi: scmIntegrationsApiRef, + fetchApi: fetchApiRef, + identityApi: identityApiRef, + }, + factory: ({ discoveryApi, scmIntegrationsApi, fetchApi, identityApi }) => + new ScaffolderClient({ + discoveryApi, + scmIntegrationsApi, + fetchApi, + identityApi, + }), + }), + }, +}); diff --git a/plugins/scaffolder/src/alpha/hooks/index.ts b/plugins/scaffolder/src/alpha/hooks/index.ts new file mode 100644 index 0000000000..fd9b0f7912 --- /dev/null +++ b/plugins/scaffolder/src/alpha/hooks/index.ts @@ -0,0 +1,16 @@ +/* + * 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. + */ +export * from './useFormDecorators'; diff --git a/plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx new file mode 100644 index 0000000000..92475c3eea --- /dev/null +++ b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.test.tsx @@ -0,0 +1,84 @@ +/* + * 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 { DefaultScaffolderFormDecoratorsApi } from '../api/FormDecoratorsApi'; +import { createScaffolderFormDecorator } from '@backstage/plugin-scaffolder-react/alpha'; +import { createApiRef, errorApiRef } from '@backstage/core-plugin-api'; + +import { TestApiProvider } from '@backstage/test-utils'; +import { renderHook, waitFor } from '@testing-library/react'; +import { useFormDecorators } from './useFormDecorators'; +import React from 'react'; +import { formDecoratorsApiRef } from '../api/ref'; +import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; + +describe('useFormDecorators', () => { + const mockApiRef = createApiRef<{ + test: (input: string) => void; + }>({ id: 'test' }); + + const mockApiImplementation = { test: jest.fn() }; + + const mockDecorator = createScaffolderFormDecorator({ + id: 'test', + deps: { mockApiRef }, + schema: { + input: { + test: z => z.string(), + }, + }, + async decorator({ input: { test } }, { mockApiRef: mock }) { + mock.test(test); + }, + }); + + const manifest: TemplateParameterSchema = { + EXPERIMENTAL_formDecorators: [{ id: 'test', input: { test: 'hello' } }], + steps: [], + title: 'test', + }; + + it('should run the form decorators for a given manifest with the correct input', async () => { + const renderedHook = renderHook(() => useFormDecorators({ manifest }), { + wrapper: ({ children }) => ( + {} }], + ]} + > + {children} + + ), + }); + + await waitFor(async () => { + const result = renderedHook.result.current!; + + await result.run({ + formState: {}, + secrets: {}, + }); + + expect(mockApiImplementation.test).toHaveBeenCalledWith('hello'); + }); + }); +}); diff --git a/plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts new file mode 100644 index 0000000000..8469a89bec --- /dev/null +++ b/plugins/scaffolder/src/alpha/hooks/useFormDecorators.ts @@ -0,0 +1,117 @@ +/* + * 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 { errorApiRef, useApi, useApiHolder } from '@backstage/core-plugin-api'; +import { formDecoratorsApiRef } from '../api/ref'; +import useAsync from 'react-use/esm/useAsync'; +import { useMemo } from 'react'; +import { ScaffolderFormDecoratorContext } from '@backstage/plugin-scaffolder-react/alpha'; +import { OpaqueFormDecorator } from '@internal/scaffolder'; +import { TemplateParameterSchema } from '@backstage/plugin-scaffolder-react'; +import { JsonValue } from '@backstage/types'; + +/** @internal */ +type BoundFieldDecorator = { + decorator: (ctx: ScaffolderFormDecoratorContext) => Promise; +}; + +export const useFormDecorators = ({ + manifest, +}: { + manifest?: TemplateParameterSchema; +}) => { + const formDecoratorsApi = useApi(formDecoratorsApiRef); + const errorApi = useApi(errorApiRef); + const { value: decorators } = useAsync( + () => formDecoratorsApi.getFormDecorators(), + [], + ); + const apiHolder = useApiHolder(); + + const boundDecorators = useMemo(() => { + const decoratorsMap = new Map(); + + for (const decorator of decorators ?? []) { + try { + const { decorator: decoratorFn, deps } = + OpaqueFormDecorator.toInternal(decorator); + + const resolvedDeps = Object.entries(deps ?? {}).map(([key, value]) => { + const api = apiHolder.get(value); + if (!api) { + throw new Error( + `Failed to resolve apiRef ${value.id} for form decorator ${decorator.id} it will be disabled`, + ); + } + return [key, api]; + }); + + decoratorsMap.set(decorator.id, { + decorator: ctx => decoratorFn(ctx, Object.fromEntries(resolvedDeps)), + }); + } catch (ex) { + errorApi.post(ex); + return undefined; + } + } + return decoratorsMap; + }, [apiHolder, decorators, errorApi]); + + return { + run: async (opts: { + formState: Record; + secrets: Record; + }) => { + let formState: Record = { ...opts.formState }; + let secrets: Record = {}; + + if (manifest?.EXPERIMENTAL_formDecorators) { + // for each of the form decorators, go and call the decorator with the context + await Promise.all( + manifest.EXPERIMENTAL_formDecorators.map(async decorator => { + const formDecorator = boundDecorators?.get(decorator.id); + if (!formDecorator) { + errorApi.post( + new Error(`Failed to find form decorator ${decorator.id}`), + ); + return; + } + + await formDecorator.decorator({ + setSecrets: ( + handler: ( + oldState: Record, + ) => Record, + ) => { + secrets = { ...handler(secrets) }; + }, + setFormState: ( + handler: ( + oldState: Record, + ) => Record, + ) => { + formState = { ...handler(formState) }; + }, + formState, + input: decorator.input ?? {}, + }); + }), + ); + } + + return { formState, secrets }; + }, + }; +}; diff --git a/plugins/scaffolder/src/alpha/index.ts b/plugins/scaffolder/src/alpha/index.ts index bd3104a274..d239f44b4f 100644 --- a/plugins/scaffolder/src/alpha/index.ts +++ b/plugins/scaffolder/src/alpha/index.ts @@ -23,5 +23,11 @@ export { } from './components'; export { scaffolderTranslationRef } from '../translation'; +export * from './api'; + +export { + formFieldsApiRef, + type ScaffolderFormFieldsApi, +} from '@backstage/plugin-scaffolder-react/alpha'; export { default } from './plugin'; diff --git a/plugins/scaffolder/src/alpha/plugin.tsx b/plugins/scaffolder/src/alpha/plugin.tsx index 54e375e875..44ec1f5d4c 100644 --- a/plugins/scaffolder/src/alpha/plugin.tsx +++ b/plugins/scaffolder/src/alpha/plugin.tsx @@ -26,13 +26,13 @@ import { selectedTemplateRouteRef, viewTechDocRouteRef, } from '../routes'; -import { scaffolderApi } from './api'; import { repoUrlPickerFormField, scaffolderNavItem, scaffolderPage, + scaffolderApi, } from './extensions'; -import { formFieldsApi } from './api/FormFieldsApi'; +import { formFieldsApi } from '@backstage/plugin-scaffolder-react/alpha'; /** @alpha */ export default createFrontendPlugin({ diff --git a/plugins/scaffolder/src/api.ts b/plugins/scaffolder/src/api.ts index df032b536d..01e163bb30 100644 --- a/plugins/scaffolder/src/api.ts +++ b/plugins/scaffolder/src/api.ts @@ -22,10 +22,6 @@ import { } from '@backstage/core-plugin-api'; import { ResponseError } from '@backstage/errors'; import { ScmIntegrationRegistry } from '@backstage/integration'; -import { Observable } from '@backstage/types'; -import qs from 'qs'; -import queryString from 'qs'; -import ObservableImpl from 'zen-observable'; import { ListActionsResponse, LogEvent, @@ -40,10 +36,13 @@ import { ScaffolderTask, TemplateParameterSchema, } from '@backstage/plugin-scaffolder-react'; +import { Observable } from '@backstage/types'; import { EventSourceMessage, fetchEventSource, } from '@microsoft/fetch-event-source'; +import { default as qs, default as queryString } from 'qs'; +import ObservableImpl from 'zen-observable'; /** * An API to interact with the scaffolder backend. @@ -365,7 +364,7 @@ export class ScaffolderClient implements ScaffolderApi { provider: string; resource: string; context?: Record; - }): Promise<{ results: { title: string }[] }> { + }): Promise<{ results: { title?: string; id: string }[] }> { const baseUrl = await this.discoveryApi.getBaseUrl('scaffolder'); const url = `${baseUrl}/v2/autocomplete/${provider}/${resource}`; diff --git a/plugins/scaffolder/src/components/Router/Router.test.tsx b/plugins/scaffolder/src/components/Router/Router.test.tsx index c062c723cf..9c752ed3c1 100644 --- a/plugins/scaffolder/src/components/Router/Router.test.tsx +++ b/plugins/scaffolder/src/components/Router/Router.test.tsx @@ -15,7 +15,11 @@ */ import React from 'react'; import { Router } from './Router'; -import { renderInTestApp } from '@backstage/test-utils'; +import { + renderInTestApp, + TestApiProvider, + TestAppOptions, +} from '@backstage/test-utils'; import { createScaffolderFieldExtension, ScaffolderFieldExtensions, @@ -26,12 +30,26 @@ import { ScaffolderLayouts, } from '@backstage/plugin-scaffolder-react'; import { TemplateListPage, TemplateWizardPage } from '../../alpha/components'; +import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; jest.mock('../../alpha/components', () => ({ TemplateWizardPage: jest.fn(() => null), TemplateListPage: jest.fn(() => null), })); +const wrapInApisAndRender = ( + element: React.ReactElement, + opts?: TestAppOptions, +) => + renderInTestApp( + [] }]]} + > + {element} + , + opts, + ); + describe('Router', () => { beforeEach(() => { (TemplateWizardPage as jest.Mock).mockClear(); @@ -39,13 +57,13 @@ describe('Router', () => { }); describe('/', () => { it('should render the TemplateListPage', async () => { - await renderInTestApp(); + await wrapInApisAndRender(); expect(TemplateListPage).toHaveBeenCalled(); }); it('should render user-provided TemplateListPage', async () => { - const { getByText } = await renderInTestApp( + const { getByText } = await wrapInApisAndRender( <>foobar, @@ -62,7 +80,7 @@ describe('Router', () => { describe('/templates/:templateName', () => { it('should render the TemplateWizard page', async () => { - await renderInTestApp(, { + await wrapInApisAndRender(, { routeEntries: ['/templates/default/foo'], }); @@ -70,7 +88,7 @@ describe('Router', () => { }); it('should render user-provided TemplateWizardPage', async () => { - const { getByText } = await renderInTestApp( + const { getByText } = await wrapInApisAndRender( <>foobar, @@ -87,13 +105,14 @@ describe('Router', () => { it('should pass through the FormProps property', async () => { const transformErrorsMock = jest.fn(); - await renderInTestApp( + await wrapInApisAndRender( , + { routeEntries: ['/templates/default/foo'], }, @@ -118,7 +137,7 @@ describe('Router', () => { }), ); - await renderInTestApp( + await wrapInApisAndRender( @@ -146,7 +165,7 @@ describe('Router', () => { }), ); - await renderInTestApp( + await wrapInApisAndRender( diff --git a/plugins/scaffolder/src/components/Router/Router.tsx b/plugins/scaffolder/src/components/Router/Router.tsx index 79684a694d..6c06322867 100644 --- a/plugins/scaffolder/src/components/Router/Router.tsx +++ b/plugins/scaffolder/src/components/Router/Router.tsx @@ -60,8 +60,10 @@ import { CustomFieldsPage, } from '../../alpha/components/TemplateEditorPage'; import { RequirePermission } from '@backstage/plugin-permission-react'; -import { taskReadPermission } from '@backstage/plugin-scaffolder-common/alpha'; -import { templateManagementPermission } from '@backstage/plugin-scaffolder-common/alpha'; +import { + taskReadPermission, + templateManagementPermission, +} from '@backstage/plugin-scaffolder-common/alpha'; /** * The Props for the Scaffolder Router diff --git a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx index 26853d6d05..aa3b0e0c20 100644 --- a/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoBranchPicker/BitbucketRepoBranchPicker.tsx @@ -14,15 +14,15 @@ * limitations under the License. */ +import { useApi } from '@backstage/core-plugin-api'; import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; -import React, { useCallback, useState } from 'react'; +import FormHelperText from '@material-ui/core/FormHelperText'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; +import React, { useCallback, useState } from 'react'; import useDebounce from 'react-use/esm/useDebounce'; -import { useApi } from '@backstage/core-plugin-api'; import { BaseRepoBranchPickerProps } from './types'; -import FormHelperText from '@material-ui/core/FormHelperText'; /** * The underlying component that is rendered in the form for the `BitbucketRepoBranchPicker` @@ -66,7 +66,7 @@ export const BitbucketRepoBranchPicker = ({ provider: 'bitbucket-cloud', }) .then(({ results }) => { - setAvailableBranches(results.map(r => r.title)); + setAvailableBranches(results.map(r => r.title!)); }) .catch(() => { setAvailableBranches([]); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx index 05d04886e4..af3952ff51 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.test.tsx @@ -14,22 +14,22 @@ * limitations under the License. */ -import React from 'react'; -import { BitbucketRepoPicker } from './BitbucketRepoPicker'; -import { fireEvent, waitFor } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; -import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; import { ScaffolderApi, scaffolderApiRef, } from '@backstage/plugin-scaffolder-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { fireEvent, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import React from 'react'; import { act } from 'react-dom/test-utils'; +import { BitbucketRepoPicker } from './BitbucketRepoPicker'; describe('BitbucketRepoPicker', () => { const scaffolderApiMock: Partial = { autocomplete: jest.fn().mockImplementation(opts => Promise.resolve({ - results: [{ title: `${opts.resource}_example` }], + results: [{ id: `${opts.resource}_example` }], }), ), }; @@ -266,7 +266,7 @@ describe('BitbucketRepoPicker', () => { // Verify that the available repos are updated await waitFor(() => expect(onChange).toHaveBeenCalledWith({ - availableRepos: ['repositories_example'], + availableRepos: [{ name: 'repositories_example' }], }), ); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx index 28cd0cf5bc..45a6439a63 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/BitbucketRepoPicker.tsx @@ -13,18 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useCallback, useEffect, useState } from 'react'; +import { Select, SelectItem } from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; -import { Select, SelectItem } from '@backstage/core-components'; -import { BaseRepoUrlPickerProps } from './types'; -import Autocomplete from '@material-ui/lab/Autocomplete'; import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import React, { useCallback, useEffect, useState } from 'react'; import useDebounce from 'react-use/esm/useDebounce'; -import { useApi } from '@backstage/core-plugin-api'; -import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; -import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import { scaffolderTranslationRef } from '../../../translation'; +import { BaseRepoUrlPickerProps } from './types'; /** * The underlying component that is rendered in the form for the `BitbucketRepoPicker` @@ -89,7 +89,7 @@ export const BitbucketRepoPicker = ( provider: 'bitbucket-cloud', }) .then(({ results }) => { - setAvailableWorkspaces(results.map(r => r.title)); + setAvailableWorkspaces(results.map(r => r.id)); }) .catch(() => { setAvailableWorkspaces([]); @@ -118,7 +118,7 @@ export const BitbucketRepoPicker = ( provider: 'bitbucket-cloud', }) .then(({ results }) => { - setAvailableProjects(results.map(r => r.title)); + setAvailableProjects(results.map(r => r.id)); }) .catch(() => { setAvailableProjects([]); @@ -148,7 +148,11 @@ export const BitbucketRepoPicker = ( provider: 'bitbucket-cloud', }) .then(({ results }) => { - onChange({ availableRepos: results.map(r => r.title) }); + onChange({ + availableRepos: results.map(r => { + return { name: r.id }; + }), + }); }) .catch(() => { onChange({ availableRepos: [] }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx index f3d6e2da91..a8fb42cae3 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.test.tsx @@ -14,22 +14,36 @@ * limitations under the License. */ +import { + ScaffolderApi, + scaffolderApiRef, +} from '@backstage/plugin-scaffolder-react'; +import { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { fireEvent } from '@testing-library/react'; import React from 'react'; import { GitlabRepoPicker } from './GitlabRepoPicker'; -import { fireEvent } from '@testing-library/react'; -import { renderInTestApp } from '@backstage/test-utils'; describe('GitlabRepoPicker', () => { + const scaffolderApiMock: Partial = { + autocomplete: jest.fn().mockImplementation(opts => + Promise.resolve({ + results: [{ title: `${opts.resource}_example` }], + }), + ), + }; describe('owner field', () => { it('renders a select if there is a list of allowed owners', async () => { const allowedOwners = ['owner1', 'owner2']; const { findByText } = await renderInTestApp( - , + + + , + , ); expect(await findByText('owner1')).toBeInTheDocument(); @@ -40,12 +54,15 @@ describe('GitlabRepoPicker', () => { const onChange = jest.fn(); const allowedOwners = ['owner1', 'owner2']; const { getByRole } = await renderInTestApp( - , + + + , + , ); await fireEvent.change(getByRole('combobox'), { @@ -59,12 +76,15 @@ describe('GitlabRepoPicker', () => { const onChange = jest.fn(); const allowedOwners = ['owner1']; const { getByRole } = await renderInTestApp( - , + + + , + , ); expect(getByRole('combobox')).toBeDisabled(); @@ -73,14 +93,20 @@ describe('GitlabRepoPicker', () => { it('should display free text if no allowed owners are passed', async () => { const onChange = jest.fn(); const { getAllByRole } = await renderInTestApp( - , + + + , ); const ownerField = getAllByRole('textbox')[0]; - fireEvent.change(ownerField, { target: { value: 'my-mock-owner' } }); + ownerField.focus(); + fireEvent.change(ownerField, { + target: { value: 'my-mock-owner' }, + }); + ownerField.blur(); expect(onChange).toHaveBeenCalledWith({ owner: 'my-mock-owner' }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx index c0879008a1..d97c9431ee 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/GitlabRepoPicker.tsx @@ -13,28 +13,101 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; +import { Select, SelectItem } from '@backstage/core-components'; +import { useApi } from '@backstage/core-plugin-api'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import { scaffolderApiRef } from '@backstage/plugin-scaffolder-react'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; import TextField from '@material-ui/core/TextField'; -import { Select, SelectItem } from '@backstage/core-components'; -import { BaseRepoUrlPickerProps } from './types'; -import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import React, { useCallback, useState } from 'react'; +import useDebounce from 'react-use/esm/useDebounce'; import { scaffolderTranslationRef } from '../../../translation'; +import { BaseRepoUrlPickerProps } from './types'; export const GitlabRepoPicker = ( props: BaseRepoUrlPickerProps<{ allowedOwners?: string[]; allowedRepos?: string[]; + accessToken?: string; }>, ) => { - const { allowedOwners = [], state, onChange, rawErrors } = props; + const { allowedOwners = [], state, onChange, rawErrors, accessToken } = props; + const [availableGroups, setAvailableGroups] = useState< + { title: string; id: string }[] + >([]); const { t } = useTranslationRef(scaffolderTranslationRef); const ownerItems: SelectItem[] = allowedOwners ? allowedOwners.map(i => ({ label: i, value: i })) : [{ label: 'Loading...', value: 'loading' }]; - const { owner } = state; + const { owner, host } = state; + + const scaffolderApi = useApi(scaffolderApiRef); + + const updateAvailableGroups = useCallback(() => { + if (!scaffolderApi.autocomplete || !accessToken || !host) { + setAvailableGroups([]); + return; + } + + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'groups', + provider: 'gitlab', + context: { host }, + }) + .then(({ results }) => { + setAvailableGroups( + results.map(r => { + return { + title: r.title!, + id: r.id, + }; + }), + ); + }) + .catch(() => { + setAvailableGroups([]); + }); + }, [scaffolderApi, accessToken, host]); + + useDebounce(updateAvailableGroups, 500, [updateAvailableGroups]); + + // Update available repositories when client is available and group changes + const updateAvailableRepositories = useCallback(() => { + if (!scaffolderApi.autocomplete || !accessToken || !host || !owner) { + onChange({ availableRepos: [] }); + return; + } + + const selectedGroup = availableGroups.find(group => group.title === owner); + + scaffolderApi + .autocomplete({ + token: accessToken, + resource: 'repositories', + context: { + id: selectedGroup?.id ?? '', + host, + }, + provider: 'gitlab', + }) + .then(({ results }) => { + onChange({ + availableRepos: results.map(r => { + return { name: r.title!, id: r.id }; + }), + }); + }) + .catch(() => { + onChange({ availableRepos: [] }); + }); + }, [scaffolderApi, accessToken, host, owner, onChange, availableGroups]); + + useDebounce(updateAvailableRepositories, 500, [updateAvailableRepositories]); return ( <> @@ -64,12 +137,21 @@ export const GitlabRepoPicker = ( ) : ( - onChange({ owner: e.target.value })} - helperText={t('fields.gitlabRepoPicker.owner.description')} + { + onChange({ owner: newValue || '' }); + }} + options={availableGroups.map(group => group.title)} + renderInput={params => ( + + )} + freeSolo + autoSelect /> )} diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx index 3c9ca9c2ca..18da234012 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPicker.tsx @@ -15,26 +15,26 @@ */ import { useApi } from '@backstage/core-plugin-api'; import { - scmIntegrationsApiRef, scmAuthApiRef, + scmIntegrationsApiRef, } from '@backstage/integration-react'; -import React, { useEffect, useState, useMemo, useCallback } from 'react'; -import { GithubRepoPicker } from './GithubRepoPicker'; -import { GiteaRepoPicker } from './GiteaRepoPicker'; -import { GitlabRepoPicker } from './GitlabRepoPicker'; -import { AzureRepoPicker } from './AzureRepoPicker'; -import { BitbucketRepoPicker } from './BitbucketRepoPicker'; -import { GerritRepoPicker } from './GerritRepoPicker'; -import { RepoUrlPickerHost } from './RepoUrlPickerHost'; -import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; -import { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils'; -import { RepoUrlPickerFieldSchema } from './schema'; -import { RepoUrlPickerState } from './types'; -import useDebounce from 'react-use/esm/useDebounce'; import { useTemplateSecrets } from '@backstage/plugin-scaffolder-react'; import Box from '@material-ui/core/Box'; import Divider from '@material-ui/core/Divider'; import Typography from '@material-ui/core/Typography'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import useDebounce from 'react-use/esm/useDebounce'; +import { AzureRepoPicker } from './AzureRepoPicker'; +import { BitbucketRepoPicker } from './BitbucketRepoPicker'; +import { GerritRepoPicker } from './GerritRepoPicker'; +import { GiteaRepoPicker } from './GiteaRepoPicker'; +import { GithubRepoPicker } from './GithubRepoPicker'; +import { GitlabRepoPicker } from './GitlabRepoPicker'; +import { RepoUrlPickerHost } from './RepoUrlPickerHost'; +import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; +import { RepoUrlPickerFieldSchema } from './schema'; +import { RepoUrlPickerState } from './types'; +import { parseRepoPickerUrl, serializeRepoPickerUrl } from './utils'; export { RepoUrlPickerSchema } from './schema'; @@ -203,6 +203,10 @@ export const RepoUrlPicker = ( rawErrors={rawErrors} state={state} onChange={updateLocalState} + accessToken={ + uiSchema?.['ui:options']?.requestUserCredentials?.secretsKey && + secrets[uiSchema['ui:options'].requestUserCredentials.secretsKey] + } /> )} {hostType === 'bitbucket' && ( @@ -238,7 +242,11 @@ export const RepoUrlPicker = ( repoName={state.repoName} allowedRepos={allowedRepos} onChange={repo => - setState(prevState => ({ ...prevState, repoName: repo })) + setState(prevState => ({ + ...prevState, + repoName: repo.name, + id: repo.id || '', + })) } rawErrors={rawErrors} availableRepos={state.availableRepos} diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx index ec4853c714..f78abc2dfb 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.test.tsx @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; +import { renderInTestApp } from '@backstage/test-utils'; import { fireEvent } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import React from 'react'; import { act } from 'react-dom/test-utils'; -import { renderInTestApp } from '@backstage/test-utils'; +import { RepoUrlPickerRepoName } from './RepoUrlPickerRepoName'; describe('RepoUrlPickerRepoName', () => { it('should call onChange with the first allowed repo if there is none set already', async () => { @@ -32,7 +32,7 @@ describe('RepoUrlPickerRepoName', () => { />, ); - expect(onChange).toHaveBeenCalledWith('foo'); + expect(onChange).toHaveBeenCalledWith({ name: 'foo' }); }); it('should render a dropdown of all the options', async () => { @@ -78,11 +78,11 @@ describe('RepoUrlPickerRepoName', () => { textArea.blur(); }); - expect(onChange).toHaveBeenCalledWith('foo'); + expect(onChange).toHaveBeenCalledWith({ name: 'foo' }); }); it('should autocomplete with provided availableRepos', async () => { - const availableRepos = ['foo', 'bar']; + const availableRepos = [{ name: 'foo' }, { name: 'bar' }]; const onChange = jest.fn(); @@ -100,11 +100,11 @@ describe('RepoUrlPickerRepoName', () => { // Verify that available repos are shown for (const repo of availableRepos) { - expect(getByText(repo)).toBeInTheDocument(); + expect(getByText(repo.name)).toBeInTheDocument(); } // Verify that selecting an option calls onChange - await userEvent.click(getByText(availableRepos[0])); + await userEvent.click(getByText(availableRepos[0].name)); expect(onChange).toHaveBeenCalledWith(availableRepos[0]); }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx index b1152d3c1f..d23a4bcd86 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/RepoUrlPickerRepoName.tsx @@ -13,21 +13,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect } from 'react'; import { Select, SelectItem } from '@backstage/core-components'; +import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; import FormControl from '@material-ui/core/FormControl'; import FormHelperText from '@material-ui/core/FormHelperText'; -import Autocomplete from '@material-ui/lab/Autocomplete'; import TextField from '@material-ui/core/TextField'; -import { useTranslationRef } from '@backstage/core-plugin-api/alpha'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import React, { useEffect } from 'react'; import { scaffolderTranslationRef } from '../../../translation'; +import { AvailableRepositories } from './types'; export const RepoUrlPickerRepoName = (props: { repoName?: string; allowedRepos?: string[]; - onChange: (host: string) => void; + onChange: (chosenRepo: AvailableRepositories) => void; rawErrors: string[]; - availableRepos?: string[]; + availableRepos?: AvailableRepositories[]; }) => { const { repoName, allowedRepos, onChange, rawErrors, availableRepos } = props; const { t } = useTranslationRef(scaffolderTranslationRef); @@ -37,7 +38,7 @@ export const RepoUrlPickerRepoName = (props: { if (!repoName) { // Set the first of the allowedRepos option if that available if (allowedRepos?.length) { - onChange(allowedRepos[0]); + onChange({ name: allowedRepos[0] }); } } }, [allowedRepos, repoName, onChange]); @@ -58,7 +59,9 @@ export const RepoUrlPickerRepoName = (props: { native label={t('fields.repoUrlPicker.repository.title')} onChange={selected => - onChange(String(Array.isArray(selected) ? selected[0] : selected)) + onChange({ + name: String(Array.isArray(selected) ? selected[0] : selected), + }) } disabled={allowedRepos.length === 1} selected={repoName} @@ -68,9 +71,12 @@ export const RepoUrlPickerRepoName = (props: { { - onChange(newValue || ''); + const selectedRepo = availableRepos?.find( + r => r.name === newValue, + ); + onChange(selectedRepo || { name: newValue || '' }); }} - options={availableRepos || []} + options={(availableRepos || []).map(r => r.name)} renderInput={params => ( = T & { diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.test.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.test.ts index c90b357cf1..ce3c938e31 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.test.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.test.ts @@ -53,9 +53,10 @@ describe('utils', () => { organization: 'organization', workspace: 'workspace', project: 'backstage', + id: '1234', }), ).toBe( - 'github.com?owner=owner&repo=backstage&organization=organization&workspace=workspace&project=backstage', + 'github.com?owner=owner&repo=backstage&organization=organization&workspace=workspace&project=backstage&id=1234', ); }); }); @@ -64,7 +65,7 @@ describe('utils', () => { it('should parse a complete string', () => { expect( parseRepoPickerUrl( - 'github.com?owner=owner&repo=backstage&organization=organization&workspace=workspace&project=backstage', + 'github.com?owner=owner&repo=backstage&organization=organization&workspace=workspace&project=backstage&id=1234', ), ).toEqual({ host: 'github.com', @@ -73,6 +74,7 @@ describe('utils', () => { organization: 'organization', workspace: 'workspace', project: 'backstage', + id: '1234', }); }); }); diff --git a/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.ts b/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.ts index 408b87413b..145a3e256f 100644 --- a/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.ts +++ b/plugins/scaffolder/src/components/fields/RepoUrlPicker/utils.ts @@ -37,6 +37,9 @@ export function serializeRepoPickerUrl(data: RepoUrlPickerState) { if (data.project) { params.set('project', data.project); } + if (data.id) { + params.set('id', data.id); + } return `${data.host}?${params.toString()}`; } @@ -50,6 +53,7 @@ export function parseRepoPickerUrl( let organization = ''; let workspace = ''; let project = ''; + let id = ''; try { if (url) { @@ -60,9 +64,10 @@ export function parseRepoPickerUrl( organization = parsed.searchParams.get('organization') || ''; workspace = parsed.searchParams.get('workspace') || ''; project = parsed.searchParams.get('project') || ''; + id = parsed.searchParams.get('id') || ''; } } catch { /* ok */ } - return { host, owner, repoName, organization, workspace, project }; + return { host, owner, repoName, organization, workspace, project, id }; } diff --git a/plugins/scaffolder/src/plugin.tsx b/plugins/scaffolder/src/plugin.tsx index 8b24e86069..17592b5826 100644 --- a/plugins/scaffolder/src/plugin.tsx +++ b/plugins/scaffolder/src/plugin.tsx @@ -78,6 +78,9 @@ import { } from './components/fields/MyGroupsPicker/MyGroupsPicker'; import { RepoBranchPicker } from './components/fields/RepoBranchPicker/RepoBranchPicker'; import { RepoBranchPickerSchema } from './components/fields/RepoBranchPicker/schema'; +import { formDecoratorsApiRef } from './alpha/api/ref'; +import { DefaultScaffolderFormDecoratorsApi } from './alpha/api/FormDecoratorsApi'; +import { formFieldsApiRef } from '@backstage/plugin-scaffolder-react/alpha'; /** * The main plugin export for the scaffolder. @@ -102,6 +105,16 @@ export const scaffolderPlugin = createPlugin({ identityApi, }), }), + createApiFactory({ + api: formDecoratorsApiRef, + deps: {}, + factory: () => DefaultScaffolderFormDecoratorsApi.create(), + }), + createApiFactory({ + api: formFieldsApiRef, + deps: {}, + factory: () => ({ getFormFields: async () => [] }), + }), ], routes: { root: rootRouteRef, diff --git a/plugins/search-backend-module-catalog/CHANGELOG.md b/plugins/search-backend-module-catalog/CHANGELOG.md index 1dd8b51ad7..cc3e8edf26 100644 --- a/plugins/search-backend-module-catalog/CHANGELOG.md +++ b/plugins/search-backend-module-catalog/CHANGELOG.md @@ -1,5 +1,72 @@ # @backstage/plugin-search-backend-module-catalog +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.2.6-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## 0.2.6-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.2.5 + +### Patch Changes + +- 0b8f344: Fixed a bug where the `filter` setting of the collator was not permitted to be an array. +- 1a1e2f4: Fix search collator text formatting for catalog entities without description +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-search-common@1.2.15 + ## 0.2.5-next.3 ### Patch Changes diff --git a/plugins/search-backend-module-catalog/README.md b/plugins/search-backend-module-catalog/README.md index 607c246390..f6793b93f5 100644 --- a/plugins/search-backend-module-catalog/README.md +++ b/plugins/search-backend-module-catalog/README.md @@ -16,12 +16,10 @@ Add the collator to your backend instance, along with the search plugin itself: ```tsx // packages/backend/src/index.ts import { createBackend } from '@backstage/backend-defaults'; -import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; -import { searchModuleCatalogCollator } from '@backstage/plugin-search-backend-module-catalog/alpha'; const backend = createBackend(); -backend.add(searchPlugin); -backend.add(searchModuleCatalogCollator); +backend.add(import('@backstage/plugin-search-backend')); +backend.add(import('@backstage/plugin-search-backend-module-catalog')); backend.start(); ``` @@ -35,12 +33,8 @@ This module also has an extension point, which lets you inject advanced customiz // packages/backend/src/index.ts import { createBackend } from '@backstage/backend-defaults'; import { createBackendModule } from '@backstage/backend-plugin-api'; -import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; import { CatalogCollatorEntityTransformer } from '@backstage/plugin-search-backend-module-catalog'; -import { - searchModuleCatalogCollator, - catalogCollatorExtensionPoint, -} from '@backstage/plugin-search-backend-module-catalog/alpha'; +import { catalogCollatorExtensionPoint } from '@backstage/plugin-search-backend-module-catalog/alpha'; const customTransformer: CatalogCollatorEntityTransformer = entity => ({ title: entity.metadata.title || entity.metadata.name, @@ -54,8 +48,8 @@ const customTransformer: CatalogCollatorEntityTransformer = entity => ({ }); const backend = createBackend(); -backend.add(searchPlugin); -backend.add(searchModuleCatalogCollator); +backend.add(import('@backstage/plugin-search-backend')); +backend.add(import('@backstage/plugin-search-backend-module-catalog')); backend.add( createBackendModule({ pluginId: 'search', @@ -63,7 +57,7 @@ backend.add( register(reg) { reg.registerInit({ deps: { collator: catalogCollatorExtensionPoint }, - init({ collator }) { + async init({ collator }) { collator.setEntityTransformer(customTransformer); }, }); diff --git a/plugins/search-backend-module-catalog/package.json b/plugins/search-backend-module-catalog/package.json index 798d4b2c11..c25990cee0 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.2.5-next.3", + "version": "0.2.6-next.2", "description": "A module for the search backend that exports catalog modules", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts index 3fe6a9c3e5..b0b7465f5b 100644 --- a/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts +++ b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.test.ts @@ -147,5 +147,34 @@ describe('DefaultCatalogCollatorEntityTransformer', () => { owner: '', }); }); + + it('sets text correctly when description is not provided', async () => { + const userEntityWithoutDescription = { + ...userEntity, + metadata: { + ...userEntity.metadata, + description: undefined, + }, + spec: { + profile: { + ...userEntity.spec.profile, + email: undefined, + }, + }, + }; + + const document = defaultCatalogCollatorEntityTransformer( + userEntityWithoutDescription, + ); + + expect(document).toMatchObject({ + title: userEntity.metadata.name, + text: userEntity.spec.profile.displayName, + namespace: 'default', + componentType: 'other', + lifecycle: '', + owner: '', + }); + }); }); }); diff --git a/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts index db239b8669..8acc3e24b8 100644 --- a/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts +++ b/plugins/search-backend-module-catalog/src/collators/defaultCatalogCollatorEntityTransformer.ts @@ -19,7 +19,9 @@ import { CatalogCollatorEntityTransformer } from './CatalogCollatorEntityTransfo const getDocumentText = (entity: Entity): string => { const documentTexts: string[] = []; - documentTexts.push(entity.metadata.description || ''); + if (entity.metadata.description) { + documentTexts.push(entity.metadata.description); + } if (isUserEntity(entity) || isGroupEntity(entity)) { if (entity.spec?.profile?.displayName) { diff --git a/plugins/search-backend-module-elasticsearch/CHANGELOG.md b/plugins/search-backend-module-elasticsearch/CHANGELOG.md index 9a80387821..4e6344382b 100644 --- a/plugins/search-backend-module-elasticsearch/CHANGELOG.md +++ b/plugins/search-backend-module-elasticsearch/CHANGELOG.md @@ -1,5 +1,52 @@ # @backstage/plugin-search-backend-module-elasticsearch +## 1.6.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 1.6.3-next.1 + +### Patch Changes + +- 991c9fe: Update the ElasticSearchSearchEngine translator to handle phrase searches. +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + +## 1.6.3-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 1.6.2 + +### Patch Changes + +- dae59c1: Updated dependency `@short.io/opensearch-mock` to `^0.4.0`. +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + ## 1.6.2-next.3 ### Patch Changes diff --git a/plugins/search-backend-module-elasticsearch/package.json b/plugins/search-backend-module-elasticsearch/package.json index 144fc79175..b53dd1f095 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.6.2-next.3", + "version": "1.6.3-next.2", "description": "A module for the search backend that implements search using ElasticSearch", "backstage": { "role": "backend-plugin-module", diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts index 3f64e0b768..379b712469 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.test.ts @@ -185,12 +185,11 @@ describe('ElasticSearchSearchEngine', () => { expect(queryBody).toEqual({ query: { bool: { - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, filter: { @@ -205,6 +204,56 @@ describe('ElasticSearchSearchEngine', () => { }); }); + it('should return translated query with phrase terms', async () => { + const translatorUnderTest = inspectableSearchEngine.getTranslator(); + + const actualTranslatedQuery = translatorUnderTest({ + types: ['indexName'], + term: '"test phrase" anotherTerm "another phrase"', + filters: {}, + }) as ElasticSearchConcreteQuery; + + expect(actualTranslatedQuery).toMatchObject({ + documentTypes: ['indexName'], + elasticSearchQuery: expect.any(Object), + }); + + const queryBody = actualTranslatedQuery.elasticSearchQuery; + + expect(queryBody).toEqual({ + query: { + bool: { + should: [ + { + multi_match: { + query: 'test phrase', + fields: ['*'], + type: 'phrase', + }, + }, + { + multi_match: { + query: 'another phrase', + fields: ['*'], + type: 'phrase', + }, + }, + { + multi_match: { + query: 'anotherTerm', + fields: ['*'], + fuzziness: 'auto', + }, + }, + ], + filter: [], + }, + }, + from: 0, + size: 25, + }); + }); + it('should pass page cursor', async () => { const translatorUnderTest = inspectableSearchEngine.getTranslator(); @@ -225,12 +274,11 @@ describe('ElasticSearchSearchEngine', () => { query: { bool: { filter: [], - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, }, @@ -264,12 +312,11 @@ describe('ElasticSearchSearchEngine', () => { expect(queryBody).toEqual({ query: { bool: { - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, filter: [ @@ -320,12 +367,11 @@ describe('ElasticSearchSearchEngine', () => { expect(queryBody).toEqual({ query: { bool: { - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, filter: { @@ -382,12 +428,11 @@ describe('ElasticSearchSearchEngine', () => { query: { bool: { filter: [], - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, }, @@ -708,12 +753,11 @@ describe('ElasticSearchSearchEngine', () => { body: { query: { bool: { - must: { + should: { multi_match: { query: 'testTerm', fields: ['*'], fuzziness: 'auto', - minimum_should_match: 1, }, }, filter: [], @@ -747,7 +791,7 @@ describe('ElasticSearchSearchEngine', () => { body: { query: { bool: { - must: { + should: { match_all: {}, }, filter: [], @@ -782,7 +826,7 @@ describe('ElasticSearchSearchEngine', () => { body: { query: { bool: { - must: { + should: { match_all: {}, }, filter: [], diff --git a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts index e2934da404..16233a5e78 100644 --- a/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts +++ b/plugins/search-backend-module-elasticsearch/src/engines/ElasticSearchSearchEngine.ts @@ -246,18 +246,40 @@ export class ElasticSearchSearchEngine implements SearchEngine { 'Failed to add filters to query. Unrecognized filter type', ); }); - const esbQuery = isBlank(term) - ? esb.matchAllQuery() - : esb - .multiMatchQuery(['*'], term) - .fuzziness('auto') - .minimumShouldMatch(1); + + const esbQueries = []; + // https://regex101.com/r/Lr0MqS/1 + const phraseTerms = term.match(/"[^"]*"/g); + + if (isBlank(term)) { + const esbQuery = esb.matchAllQuery(); + esbQueries.push(esbQuery); + } else if (phraseTerms && phraseTerms.length > 0) { + let restTerm = term; + for (const phraseTerm of phraseTerms) { + restTerm = restTerm.replace(phraseTerm, ''); + const esbPhraseQuery = esb + .multiMatchQuery(['*'], phraseTerm.replace(/"/g, '')) + .type('phrase'); + esbQueries.push(esbPhraseQuery); + } + if (restTerm?.length > 0) { + const esbRestQuery = esb + .multiMatchQuery(['*'], restTerm.trim()) + .fuzziness('auto'); + esbQueries.push(esbRestQuery); + } + } else { + const esbQuery = esb.multiMatchQuery(['*'], term).fuzziness('auto'); + esbQueries.push(esbQuery); + } + const pageSize = query.pageLimit || 25; const { page } = decodePageCursor(pageCursor); let esbRequestBodySearch = esb .requestBodySearch() - .query(esb.boolQuery().filter(filter).must([esbQuery])) + .query(esb.boolQuery().filter(filter).should(esbQueries)) .from(page * pageSize) .size(pageSize); diff --git a/plugins/search-backend-module-explore/CHANGELOG.md b/plugins/search-backend-module-explore/CHANGELOG.md index 4a9091cd25..ba73639260 100644 --- a/plugins/search-backend-module-explore/CHANGELOG.md +++ b/plugins/search-backend-module-explore/CHANGELOG.md @@ -1,5 +1,48 @@ # @backstage/plugin-search-backend-module-explore +## 0.2.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.2.6-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.2.6-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.2.5 + +### Patch Changes + +- a9a7c7c: Updated dependency `@backstage-community/plugin-explore-common` to `^0.0.7`. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + ## 0.2.5-next.3 ### Patch Changes diff --git a/plugins/search-backend-module-explore/README.md b/plugins/search-backend-module-explore/README.md index d91ee92163..aaf6aabeb9 100644 --- a/plugins/search-backend-module-explore/README.md +++ b/plugins/search-backend-module-explore/README.md @@ -16,12 +16,10 @@ Add the collator to your backend instance, along with the search plugin itself: ```tsx // packages/backend/src/index.ts import { createBackend } from '@backstage/backend-defaults'; -import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; -import { searchModuleExploreCollator } from '@backstage/plugin-search-backend-module-explore/alpha'; const backend = createBackend(); -backend.add(searchPlugin); -backend.add(searchModuleExploreCollator); +backend.add(import('@backstage/plugin-search-backend')); +backend.add(import('@backstage/plugin-search-backend-module-explore')); backend.start(); ``` diff --git a/plugins/search-backend-module-explore/package.json b/plugins/search-backend-module-explore/package.json index b2f60a119b..6adf7c2dd3 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.2.5-next.3", + "version": "0.2.6-next.2", "description": "A module for the search backend that exports explore modules", "backstage": { "role": "backend-plugin-module", @@ -53,8 +53,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", - "@backstage/plugin-search-common": "workspace:^", - "node-fetch": "^2.7.0" + "@backstage/plugin-search-common": "workspace:^" }, "devDependencies": { "@backstage/backend-test-utils": "workspace:^", diff --git a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts index da047fe8ab..bafbb9cbfe 100644 --- a/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts +++ b/plugins/search-backend-module-explore/src/collators/ToolDocumentCollatorFactory.ts @@ -29,7 +29,6 @@ import { DocumentCollatorFactory, IndexableDocument, } from '@backstage/plugin-search-common'; -import fetch from 'node-fetch'; import { Readable } from 'stream'; /** diff --git a/plugins/search-backend-module-pg/CHANGELOG.md b/plugins/search-backend-module-pg/CHANGELOG.md index fbe742820e..c922d8ac0e 100644 --- a/plugins/search-backend-module-pg/CHANGELOG.md +++ b/plugins/search-backend-module-pg/CHANGELOG.md @@ -1,5 +1,46 @@ # @backstage/plugin-search-backend-module-pg +## 0.5.39-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.5.39-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.5.39-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.5.38 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + ## 0.5.38-next.3 ### Patch Changes diff --git a/plugins/search-backend-module-pg/package.json b/plugins/search-backend-module-pg/package.json index a0699de87e..cc9ee21240 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.38-next.3", + "version": "0.5.39-next.2", "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 4a8a950243..15d4ca465b 100644 --- a/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md +++ b/plugins/search-backend-module-stack-overflow-collator/CHANGELOG.md @@ -1,5 +1,47 @@ # @backstage/plugin-search-backend-module-stack-overflow-collator +## 0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.3.4-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.3.3 + +### Patch Changes + +- 5d74716: Remove unused backend-common dependency +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-search-common@1.2.15 + ## 0.3.3-next.3 ### 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 cc71bb8cc1..6138afa68d 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.3-next.3", + "version": "0.3.4-next.2", "description": "A module for the search backend that exports stack overflow modules", "backstage": { "role": "backend-plugin-module", @@ -39,7 +39,6 @@ "@backstage/config": "workspace:^", "@backstage/plugin-search-backend-node": "workspace:^", "@backstage/plugin-search-common": "workspace:^", - "node-fetch": "^2.7.0", "qs": "^6.9.4" }, "devDependencies": { diff --git a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts index 33ceb4f870..af9a2a852b 100644 --- a/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts +++ b/plugins/search-backend-module-stack-overflow-collator/src/collators/StackOverflowQuestionsCollatorFactory.ts @@ -20,7 +20,7 @@ import { } from '@backstage/plugin-search-common'; import { Config } from '@backstage/config'; import { Readable } from 'stream'; -import fetch from 'node-fetch'; + import qs from 'qs'; import { LoggerService } from '@backstage/backend-plugin-api'; diff --git a/plugins/search-backend-module-techdocs/CHANGELOG.md b/plugins/search-backend-module-techdocs/CHANGELOG.md index fc254c7848..6c95c3a9e0 100644 --- a/plugins/search-backend-module-techdocs/CHANGELOG.md +++ b/plugins/search-backend-module-techdocs/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-search-backend-module-techdocs +## 0.3.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/plugin-catalog-node@1.15.0-next.2 + - @backstage/plugin-techdocs-node@1.12.15-next.2 + - @backstage/catalog-client@1.9.0-next.2 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-catalog-common@1.1.2-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 0.3.4-next.1 + +### Patch Changes + +- 5c9cc05: Use native fetch instead of node-fetch +- Updated dependencies + - @backstage/plugin-catalog-node@1.15.0-next.1 + - @backstage/catalog-client@1.9.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-node@1.12.15-next.1 + +## 0.3.4-next.0 + +### Patch Changes + +- ed0aaec: Update README +- Updated dependencies + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-techdocs-node@1.12.15-next.0 + - @backstage/catalog-client@1.8.1-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-catalog-node@1.14.1-next.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 0.3.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-client@1.8.0 + - @backstage/config@1.3.0 + - @backstage/plugin-catalog-node@1.14.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/catalog-model@1.7.1 + - @backstage/plugin-catalog-common@1.1.1 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-node@1.12.13 + ## 0.3.2-next.3 ### Patch Changes diff --git a/plugins/search-backend-module-techdocs/README.md b/plugins/search-backend-module-techdocs/README.md index 63094cca7d..341d5b858a 100644 --- a/plugins/search-backend-module-techdocs/README.md +++ b/plugins/search-backend-module-techdocs/README.md @@ -16,12 +16,10 @@ Add the collator to your backend instance, along with the search plugin itself: ```tsx // packages/backend/src/index.ts import { createBackend } from '@backstage/backend-defaults'; -import { searchPlugin } from '@backstage/plugin-search-backend/alpha'; -import { searchModuleTechDocsCollator } from '@backstage/plugin-search-backend-module-techdocs/alpha'; const backend = createBackend(); -backend.add(searchPlugin); -backend.add(searchModuleTechDocsCollator); +backend.add(import('@backstage/plugin-search-backend')); +backend.add(import('@backstage/plugin-search-backend-module-techdocs')); backend.start(); ``` diff --git a/plugins/search-backend-module-techdocs/package.json b/plugins/search-backend-module-techdocs/package.json index cb55aaee2e..e519fbc483 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.3.2-next.3", + "version": "0.3.4-next.2", "description": "A module for the search backend that exports techdocs modules", "backstage": { "role": "backend-plugin-module", @@ -60,7 +60,6 @@ "@backstage/plugin-search-common": "workspace:^", "@backstage/plugin-techdocs-node": "workspace:^", "lodash": "^4.17.21", - "node-fetch": "^2.7.0", "p-limit": "^3.1.0" }, "devDependencies": { diff --git a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts index 0b53b33b30..3a586fd306 100644 --- a/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts +++ b/plugins/search-backend-module-techdocs/src/collators/DefaultTechDocsCollatorFactory.ts @@ -34,7 +34,6 @@ import { catalogEntityReadPermission } from '@backstage/plugin-catalog-common/al import { Permission } from '@backstage/plugin-permission-common'; import { DocumentCollatorFactory } from '@backstage/plugin-search-common'; import { TechDocsDocument } from '@backstage/plugin-techdocs-node'; -import fetch from 'node-fetch'; import pLimit from 'p-limit'; import { Readable } from 'stream'; import { TechDocsCollatorEntityTransformer } from './TechDocsCollatorEntityTransformer'; diff --git a/plugins/search-backend-node/CHANGELOG.md b/plugins/search-backend-node/CHANGELOG.md index b73f9dc590..a1ad348d43 100644 --- a/plugins/search-backend-node/CHANGELOG.md +++ b/plugins/search-backend-node/CHANGELOG.md @@ -1,5 +1,53 @@ # @backstage/plugin-search-backend-node +## 1.3.6-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 1.3.6-next.1 + +### Patch Changes + +- 5ae8a2c: Removed unnecessary dependency on `@backstage/backend-defaults`. +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## 1.3.6-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## 1.3.5 + +### Patch Changes + +- 4e58bc7: Upgrade to uuid v11 internally +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-search-common@1.2.15 + ## 1.3.5-next.3 ### Patch Changes diff --git a/plugins/search-backend-node/package.json b/plugins/search-backend-node/package.json index 157576b542..be0dedcee6 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.5-next.3", + "version": "1.3.6-next.2", "description": "A library for Backstage backend plugins that want to interact with the search backend plugin", "backstage": { "role": "node-library", @@ -53,7 +53,6 @@ "test": "backstage-cli package test" }, "dependencies": { - "@backstage/backend-defaults": "workspace:^", "@backstage/backend-plugin-api": "workspace:^", "@backstage/config": "workspace:^", "@backstage/errors": "workspace:^", @@ -67,6 +66,7 @@ }, "devDependencies": { "@backstage/backend-common": "^0.25.0", + "@backstage/backend-defaults": "workspace:^", "@backstage/backend-test-utils": "workspace:^", "@backstage/cli": "workspace:^", "@types/ndjson": "^2.0.1" diff --git a/plugins/search-backend/CHANGELOG.md b/plugins/search-backend/CHANGELOG.md index 75d841d4a1..4ff7f3d774 100644 --- a/plugins/search-backend/CHANGELOG.md +++ b/plugins/search-backend/CHANGELOG.md @@ -1,5 +1,77 @@ # @backstage/plugin-search-backend +## 1.8.0-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/plugin-permission-node@0.8.6-next.2 + - @backstage/backend-openapi-utils@0.4.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 1.8.0-next.1 + +### Minor Changes + +- 384e494: Internal updates to generated code. + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/plugin-search-backend-node@1.3.6-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-permission-node@0.8.6-next.1 + - @backstage/backend-openapi-utils@0.3.1-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-search-common@1.2.15 + +## 1.7.1-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/backend-openapi-utils@0.3.1-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/plugin-permission-node@0.8.6-next.0 + - @backstage/plugin-search-backend-node@1.3.6-next.0 + - @backstage/plugin-search-common@1.2.15 + +## 1.7.0 + +### Minor Changes + +- 39fd704: Internal update to use the new generated server types from `backstage-cli package schema openapi generate --server`. + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/backend-openapi-utils@0.3.0 + - @backstage/plugin-search-backend-node@1.3.5 + - @backstage/plugin-permission-common@0.8.2 + - @backstage/errors@1.2.5 + - @backstage/plugin-permission-node@0.8.5 + - @backstage/plugin-search-common@1.2.15 + ## 1.7.0-next.3 ### Patch Changes diff --git a/plugins/search-backend/package.json b/plugins/search-backend/package.json index 2eec38fcae..b64ab4d306 100644 --- a/plugins/search-backend/package.json +++ b/plugins/search-backend/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-backend", - "version": "1.7.0-next.3", + "version": "1.8.0-next.2", "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.yaml b/plugins/search-backend/src/schema/openapi.yaml index cbf3db273a..b1b8e83f58 100644 --- a/plugins/search-backend/src/schema/openapi.yaml +++ b/plugins/search-backend/src/schema/openapi.yaml @@ -175,4 +175,4 @@ paths: allowReserved: true schema: type: object - additionalProperties: true + additionalProperties: {} diff --git a/plugins/search-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts b/plugins/search-backend/src/schema/openapi/generated/apis/Api.server.ts similarity index 96% rename from plugins/search-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts rename to plugins/search-backend/src/schema/openapi/generated/apis/Api.server.ts index 5d228b9f84..d23648d8b5 100644 --- a/plugins/search-backend/src/schema/openapi/generated/apis/DefaultApi.server.ts +++ b/plugins/search-backend/src/schema/openapi/generated/apis/Api.server.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +// + // ****************************************************************** // * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * // ****************************************************************** @@ -29,14 +31,11 @@ export type Query = { types?: Array; pageCursor?: string; pageLimit?: number; + unknown?: { [key: string]: any }; }; response: Query200Response | Error; }; -/** - * no description - */ - export type EndpointMap = { '#get|/query': Query; }; diff --git a/plugins/search-backend/src/schema/openapi/generated/apis/index.ts b/plugins/search-backend/src/schema/openapi/generated/apis/index.ts index 79855a6fc8..a3cdbbebd2 100644 --- a/plugins/search-backend/src/schema/openapi/generated/apis/index.ts +++ b/plugins/search-backend/src/schema/openapi/generated/apis/index.ts @@ -14,4 +14,10 @@ * limitations under the License. */ -export * from './DefaultApi.server'; +// + +// ****************************************************************** +// * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. * +// ****************************************************************** + +export * from './Api.server'; diff --git a/plugins/search-backend/src/schema/openapi/generated/router.ts b/plugins/search-backend/src/schema/openapi/generated/router.ts index 8d55dfeef2..a7dd980142 100644 --- a/plugins/search-backend/src/schema/openapi/generated/router.ts +++ b/plugins/search-backend/src/schema/openapi/generated/router.ts @@ -253,7 +253,7 @@ export const spec = { allowReserved: true, schema: { type: 'object', - additionalProperties: true, + additionalProperties: {}, }, }, ], diff --git a/plugins/search-common/CHANGELOG.md b/plugins/search-common/CHANGELOG.md index 3bdf90fe85..279d2450de 100644 --- a/plugins/search-common/CHANGELOG.md +++ b/plugins/search-common/CHANGELOG.md @@ -1,5 +1,21 @@ # @backstage/plugin-search-common +## 1.2.16-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.3-next.0 + +## 1.2.15 + +### Patch Changes + +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-permission-common@0.8.2 + ## 1.2.14 ### Patch Changes diff --git a/plugins/search-common/package.json b/plugins/search-common/package.json index 10524c1515..ece78fae8c 100644 --- a/plugins/search-common/package.json +++ b/plugins/search-common/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-common", - "version": "1.2.14", + "version": "1.2.16-next.0", "description": "Common functionalities for Search, to be shared between various search-enabled plugins", "backstage": { "role": "common-library", diff --git a/plugins/search-react/CHANGELOG.md b/plugins/search-react/CHANGELOG.md index 4b802bc04c..b49d54c56b 100644 --- a/plugins/search-react/CHANGELOG.md +++ b/plugins/search-react/CHANGELOG.md @@ -1,5 +1,58 @@ # @backstage/plugin-search-react +## 1.8.4-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.16-next.0 + +## 1.8.4-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## 1.8.4-next.0 + +### Patch Changes + +- d311c84: Use Select from core-components and update Lifecycle filter to use Select instead checkboxes. +- Updated dependencies + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## 1.8.2 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/core-components@0.16.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + ## 1.8.2-next.2 ### Patch Changes diff --git a/plugins/search-react/package.json b/plugins/search-react/package.json index 1802dacf5f..163165fe37 100644 --- a/plugins/search-react/package.json +++ b/plugins/search-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search-react", - "version": "1.8.2-next.2", + "version": "1.8.4-next.2", "backstage": { "role": "web-library", "pluginId": "search", @@ -68,7 +68,8 @@ "@material-ui/lab": "4.0.0-alpha.61", "lodash": "^4.17.21", "qs": "^6.9.4", - "react-use": "^17.3.2" + "react-use": "^17.3.2", + "uuid": "^11.0.2" }, "devDependencies": { "@backstage/cli": "workspace:^", diff --git a/plugins/search-react/src/components/SearchFilter/SearchFilter.test.tsx b/plugins/search-react/src/components/SearchFilter/SearchFilter.test.tsx index e155a093d5..e28558b73a 100644 --- a/plugins/search-react/src/components/SearchFilter/SearchFilter.test.tsx +++ b/plugins/search-react/src/components/SearchFilter/SearchFilter.test.tsx @@ -289,12 +289,14 @@ describe('SearchFilter', () => { expect(screen.getByRole('listbox')).toBeInTheDocument(); }); - expect( - screen.getByRole('option', { name: values[0] }), - ).toBeInTheDocument(); - expect( - screen.getByRole('option', { name: values[1] }), - ).toBeInTheDocument(); + await waitFor(() => { + expect( + screen.getByRole('option', { name: values[0] }), + ).toBeInTheDocument(); + expect( + screen.getByRole('option', { name: values[1] }), + ).toBeInTheDocument(); + }); }); it('Renders correctly based on filter state', async () => { diff --git a/plugins/search-react/src/components/SearchFilter/SearchFilter.tsx b/plugins/search-react/src/components/SearchFilter/SearchFilter.tsx index acfa6aec3b..f5f85f3f56 100644 --- a/plugins/search-react/src/components/SearchFilter/SearchFilter.tsx +++ b/plugins/search-react/src/components/SearchFilter/SearchFilter.tsx @@ -14,16 +14,15 @@ * limitations under the License. */ -import React, { ReactElement, ChangeEvent } from 'react'; +import React, { ReactElement, ChangeEvent, useRef } from 'react'; +import { capitalize } from 'lodash'; +import { v4 as uuid } from 'uuid'; import FormControl from '@material-ui/core/FormControl'; import FormControlLabel from '@material-ui/core/FormControlLabel'; -import InputLabel from '@material-ui/core/InputLabel'; import Checkbox from '@material-ui/core/Checkbox'; -import Select from '@material-ui/core/Select'; -import MenuItem from '@material-ui/core/MenuItem'; import FormLabel from '@material-ui/core/FormLabel'; -import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; +import { Select, SelectedItems } from '@backstage/core-components'; import { useSearch } from '../../context'; import { @@ -161,7 +160,6 @@ export const SelectFilter = (props: SearchFilterComponentProps) => { values: givenValues, valuesDebounceMs, } = props; - const classes = useStyles(); useDefaultFilterValue(name, defaultValue); const asyncValues = typeof givenValues === 'function' ? givenValues : undefined; @@ -173,19 +171,21 @@ export const SelectFilter = (props: SearchFilterComponentProps) => { defaultValues, valuesDebounceMs, ); + const allOptionValue = useRef(uuid()); + const allOption = { value: allOptionValue.current, label: 'All' }; const { filters, setFilters } = useSearch(); - const handleChange = (e: ChangeEvent<{ value: unknown }>) => { - const { - target: { value }, - } = e; - + const handleChange = (value: SelectedItems) => { setFilters(prevFilters => { const { [name]: filter, ...others } = prevFilters; - return value ? { ...others, [name]: value as string } : others; + return value !== allOptionValue.current + ? { ...others, [name]: value as string } + : others; }); }; + const items = [allOption, ...values.map(value => ({ value, label: value }))]; + return ( { fullWidth data-testid="search-selectfilter-next" > - {label ? ( - - {label} - - ) : null} + items={items} + /> ); }; diff --git a/plugins/search/CHANGELOG.md b/plugins/search/CHANGELOG.md index d120be3413..0ba1ed8577 100644 --- a/plugins/search/CHANGELOG.md +++ b/plugins/search/CHANGELOG.md @@ -1,5 +1,71 @@ # @backstage/plugin-search +## 1.4.21-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + +## 1.4.21-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + +## 1.4.21-next.0 + +### Patch Changes + +- d311c84: Use Select from core-components and update Lifecycle filter to use Select instead checkboxes. +- Updated dependencies + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + +## 1.4.19 + +### Patch Changes + +- a4ccc82: Removes the card UI from the search results type filter for a cleaner UI consistent with other filters +- Updated dependencies + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/version-bridge@1.0.10 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + ## 1.4.19-next.3 ### Patch Changes diff --git a/plugins/search/package.json b/plugins/search/package.json index 0819ec40b9..2437e82fb0 100644 --- a/plugins/search/package.json +++ b/plugins/search/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-search", - "version": "1.4.19-next.3", + "version": "1.4.21-next.2", "description": "The Backstage plugin that provides your backstage app with search", "backstage": { "role": "frontend-plugin", diff --git a/plugins/search/report-alpha.api.md b/plugins/search/report-alpha.api.md index 9b8f21fa43..d4a016bbe2 100644 --- a/plugins/search/report-alpha.api.md +++ b/plugins/search/report-alpha.api.md @@ -22,21 +22,6 @@ const _default: FrontendPlugin< }, {}, { - 'api:search': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'nav-item:search': ExtensionDefinition<{ kind: 'nav-item'; name: undefined; @@ -58,6 +43,21 @@ const _default: FrontendPlugin< routeRef: RouteRef; }; }>; + 'api:search': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; 'page:search': ExtensionDefinition<{ config: { noTrack: boolean; diff --git a/plugins/search/src/components/SearchType/SearchType.Accordion.tsx b/plugins/search/src/components/SearchType/SearchType.Accordion.tsx index d6d3578b26..2a6c2b1939 100644 --- a/plugins/search/src/components/SearchType/SearchType.Accordion.tsx +++ b/plugins/search/src/components/SearchType/SearchType.Accordion.tsx @@ -143,7 +143,7 @@ export const SearchTypeAccordion = (props: SearchTypeAccordionProps) => { return ( - + {name} { }); worker.use( - rest.get( + http.get( 'http://test-backend/static/docs/default/Component/test-entity-with-docs/search/search_index.json', - (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), + () => HttpResponse.json(mockSearchDocIndex), ), - rest.get('http://test-backend/entities', (_, res, ctx) => - res(ctx.status(200), ctx.json(expectedEntities)), + http.get('http://test-backend/entities', () => + HttpResponse.json(expectedEntities), ), ); }); @@ -164,12 +164,12 @@ describe('TechDocs Collator', () => { }); worker.use( - rest.get( + http.get( 'http://test-backend/static/docs/default/component/test-entity-with-docs/search/search_index.json', - (_, res, ctx) => res(ctx.status(200), ctx.json(mockSearchDocIndex)), + () => HttpResponse.json(mockSearchDocIndex), ), - rest.get('http://test-backend/entities', (_, res, ctx) => - res(ctx.status(200), ctx.json(expectedEntities)), + http.get('http://test-backend/entities', () => + HttpResponse.json(expectedEntities), ), ); }); diff --git a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts index 635833676c..3e852971a9 100644 --- a/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts +++ b/plugins/techdocs-backend/src/search/DefaultTechDocsCollator.ts @@ -21,7 +21,6 @@ import { RELATION_OWNED_BY, stringifyEntityRef, } from '@backstage/catalog-model'; -import fetch from 'node-fetch'; import unescape from 'lodash/unescape'; import { Logger } from 'winston'; import pLimit from 'p-limit'; diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts index a611613716..bef5a9c433 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.test.ts @@ -27,28 +27,23 @@ import * as winston from 'winston'; import { TechDocsCache } from '../cache'; import { DocsBuilder, shouldCheckForUpdate } from '../DocsBuilder'; import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer'; -import { mockServices } from '@backstage/backend-test-utils'; +import { + mockServices, + registerMswTestHooks, +} from '@backstage/backend-test-utils'; import { DiscoveryService } from '@backstage/backend-plugin-api'; +import { http, HttpResponse } from 'msw'; +import { setupServer } from 'msw/node'; jest.mock('../DocsBuilder'); jest.useFakeTimers(); -jest.mock('node-fetch', () => ({ - __esModule: true, - default: async () => { - return { - json: async () => { - return { - build_timestamp: 123, - }; - }, - }; - }, -})); - const MockedDocsBuilder = DocsBuilder as jest.MockedClass; describe('DocsSynchronizer', () => { + const worker = setupServer(); + registerMswTestHooks(worker); + const preparers: jest.Mocked = { register: jest.fn(), get: jest.fn(), @@ -101,6 +96,13 @@ describe('DocsSynchronizer', () => { scmIntegrations: ScmIntegrations.fromConfig(new ConfigReader({})), cache, }); + + worker.use( + http.get( + 'http://backstage.local/api/techdocs/static/docs/default/component/test/techdocs_metadata.json', + () => HttpResponse.json({ build_timestamp: 123 }), + ), + ); }); afterEach(() => { diff --git a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts index e4b67e920e..a1375ec142 100644 --- a/plugins/techdocs-backend/src/service/DocsSynchronizer.ts +++ b/plugins/techdocs-backend/src/service/DocsSynchronizer.ts @@ -27,7 +27,6 @@ import { PreparerBuilder, PublisherBase, } from '@backstage/plugin-techdocs-node'; -import fetch from 'node-fetch'; import pLimit, { Limit } from 'p-limit'; import { PassThrough } from 'stream'; import * as winston from 'winston'; diff --git a/plugins/techdocs-module-addons-contrib/CHANGELOG.md b/plugins/techdocs-module-addons-contrib/CHANGELOG.md index dad9e26077..53dff26045 100644 --- a/plugins/techdocs-module-addons-contrib/CHANGELOG.md +++ b/plugins/techdocs-module-addons-contrib/CHANGELOG.md @@ -1,5 +1,49 @@ # @backstage/plugin-techdocs-module-addons-contrib +## 1.1.19-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## 1.1.19-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## 1.1.19-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## 1.1.17 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/core-plugin-api@1.10.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + ## 1.1.17-next.2 ### Patch Changes diff --git a/plugins/techdocs-module-addons-contrib/package.json b/plugins/techdocs-module-addons-contrib/package.json index bf57d73750..38409d7da1 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.17-next.2", + "version": "1.1.19-next.2", "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 f485b466d7..aaa30561a0 100644 --- a/plugins/techdocs-node/CHANGELOG.md +++ b/plugins/techdocs-node/CHANGELOG.md @@ -1,5 +1,62 @@ # @backstage/plugin-techdocs-node +## 1.12.15-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-aws-node@0.1.14-next.0 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-techdocs-common@0.1.0 + +## 1.12.15-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + +## 1.12.15-next.0 + +### Patch Changes + +- 5f04976: Fixed a bug that caused missing code in published packages. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/integration-aws-node@0.1.13 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + +## 1.12.13 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/integration-aws-node@0.1.13 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/catalog-model@1.7.1 + - @backstage/errors@1.2.5 + - @backstage/integration@1.15.2 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + ## 1.12.13-next.3 ### Patch Changes diff --git a/plugins/techdocs-node/package.json b/plugins/techdocs-node/package.json index cd687e2fdd..00af4b6925 100644 --- a/plugins/techdocs-node/package.json +++ b/plugins/techdocs-node/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-node", - "version": "1.12.13-next.3", + "version": "1.12.15-next.2", "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 59ce1e5e65..f7718a56ae 100644 --- a/plugins/techdocs-react/CHANGELOG.md +++ b/plugins/techdocs-react/CHANGELOG.md @@ -1,5 +1,51 @@ # @backstage/plugin-techdocs-react +## 1.2.12-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/version-bridge@1.0.10 + +## 1.2.12-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## 1.2.12-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + +## 1.2.10 + +### Patch Changes + +- 4a2f73a: Fix an issue that caused the current documentation page to be re-rendered when navigating to + another one. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/core-components@0.16.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/version-bridge@1.0.10 + ## 1.2.10-next.2 ### Patch Changes diff --git a/plugins/techdocs-react/package.json b/plugins/techdocs-react/package.json index 9c25c0893c..63975614ca 100644 --- a/plugins/techdocs-react/package.json +++ b/plugins/techdocs-react/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs-react", - "version": "1.2.10-next.2", + "version": "1.2.12-next.2", "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 d8fdf26d05..4b26300756 100644 --- a/plugins/techdocs/CHANGELOG.md +++ b/plugins/techdocs/CHANGELOG.md @@ -1,5 +1,103 @@ # @backstage/plugin-techdocs +## 1.11.3-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/config@1.3.1-next.0 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/integration@1.16.0-next.1 + - @backstage/integration-react@1.2.2-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.2 + - @backstage/plugin-search-common@1.2.16-next.0 + - @backstage/plugin-search-react@1.8.4-next.2 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.2 + +## 1.11.3-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/integration@1.16.0-next.0 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/plugin-auth-react@0.1.10-next.1 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.4-next.1 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.1 + +## 1.11.3-next.0 + +### Patch Changes + +- 7d8777d: Added support for the Search bar in docs residing in the entity page tab, and not only the global "/docs" page. +- Updated dependencies + - @backstage/integration@1.16.0-next.0 + - @backstage/plugin-search-react@1.8.4-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/config@1.3.0 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/integration-react@1.2.2-next.0 + - @backstage/plugin-auth-react@0.1.10-next.0 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-techdocs-common@0.1.0 + - @backstage/plugin-techdocs-react@1.2.12-next.0 + +## 1.11.1 + +### Patch Changes + +- 37a7810: Fixed an issue where `` would re-render infinitely under certain conditions. +- e937ae7: Fix an issue with index page of documentation site being re-rendered. +- 90246a9: Fix techdocs config schema for custom elements sanitizer +- 605bdc0: Avoid page re-rendering when clicking on anchor links in the same documentation page. +- 4f0cb89: Added DomPurify sanitizer configuration for custom elements implementing RFC https://github.com/backstage/backstage/issues/26988. + See https://backstage.io/docs/features/techdocs/how-to-guides#how-to-enable-custom-elements-in-techdocs for how to enable it in the configuration. +- f246178: Removed `canvas` dev dependency. +- 4a2f73a: Fix an issue that caused the current documentation page to be re-rendered when navigating to + another one. +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/theme@0.6.1 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/plugin-techdocs-react@1.2.10 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/integration@1.15.2 + - @backstage/integration-react@1.2.1 + - @backstage/plugin-auth-react@0.1.8 + - @backstage/plugin-search-common@1.2.15 + - @backstage/plugin-search-react@1.8.2 + - @backstage/plugin-techdocs-common@0.1.0 + ## 1.11.1-next.3 ### Patch Changes diff --git a/plugins/techdocs/package.json b/plugins/techdocs/package.json index 7032277a95..637fc42c35 100644 --- a/plugins/techdocs/package.json +++ b/plugins/techdocs/package.json @@ -1,6 +1,6 @@ { "name": "@backstage/plugin-techdocs", - "version": "1.11.1-next.3", + "version": "1.11.3-next.2", "description": "The Backstage plugin that renders technical documentation for your components", "backstage": { "role": "frontend-plugin", diff --git a/plugins/techdocs/report-alpha.api.md b/plugins/techdocs/report-alpha.api.md index 63e078dd43..d39c9d31ed 100644 --- a/plugins/techdocs/report-alpha.api.md +++ b/plugins/techdocs/report-alpha.api.md @@ -31,21 +31,6 @@ const _default: FrontendPlugin< }, {}, { - 'api:techdocs': ExtensionDefinition<{ - kind: 'api'; - name: undefined; - config: {}; - configInput: {}; - output: ConfigurableExtensionDataRef< - AnyApiFactory, - 'core.api.factory', - {} - >; - inputs: {}; - params: { - factory: AnyApiFactory; - }; - }>; 'page:techdocs': ExtensionDefinition<{ kind: 'page'; name: undefined; @@ -97,6 +82,21 @@ const _default: FrontendPlugin< routeRef: RouteRef; }; }>; + 'api:techdocs': ExtensionDefinition<{ + kind: 'api'; + name: undefined; + config: {}; + configInput: {}; + output: ConfigurableExtensionDataRef< + AnyApiFactory, + 'core.api.factory', + {} + >; + inputs: {}; + params: { + factory: AnyApiFactory; + }; + }>; 'api:techdocs/storage': ExtensionDefinition<{ kind: 'api'; name: 'storage'; diff --git a/plugins/techdocs/report.api.md b/plugins/techdocs/report.api.md index c58a946287..c577de5eac 100644 --- a/plugins/techdocs/report.api.md +++ b/plugins/techdocs/report.api.md @@ -12,6 +12,7 @@ import { Config } from '@backstage/config'; import { CSSProperties } from '@material-ui/styles/withStyles'; import { DiscoveryApi } from '@backstage/core-plugin-api'; import { Entity } from '@backstage/catalog-model'; +import { EntityListPagination } from '@backstage/plugin-catalog-react'; import { EntityOwnerPickerProps } from '@backstage/plugin-catalog-react'; import { FetchApi } from '@backstage/core-plugin-api'; import { IdentityApi } from '@backstage/core-plugin-api'; @@ -309,6 +310,7 @@ export type TechDocsIndexPageProps = { columns?: TableColumn[]; actions?: TableProps['actions']; ownerPickerMode?: EntityOwnerPickerProps['mode']; + pagination?: EntityListPagination; }; // @public @deprecated (undocumented) @@ -371,6 +373,7 @@ export const TechDocsReaderPageContent: ( export type TechDocsReaderPageContentProps = { entityRef?: CompoundEntityRef; withSearch?: boolean; + searchResultUrlMapper?: (url: string) => string; onReady?: () => void; }; @@ -431,6 +434,7 @@ export type TechDocsSearchProps = { entityId: CompoundEntityRef; entityTitle?: string; debounceTime?: number; + searchResultUrlMapper?: (url: string) => string; }; // @public diff --git a/plugins/techdocs/src/EntityPageDocs.tsx b/plugins/techdocs/src/EntityPageDocs.tsx index 07222190ae..70a0517ded 100644 --- a/plugins/techdocs/src/EntityPageDocs.tsx +++ b/plugins/techdocs/src/EntityPageDocs.tsx @@ -25,12 +25,24 @@ import React from 'react'; import { TechDocsReaderPage } from './plugin'; import { TechDocsReaderPageContent } from './reader/components/TechDocsReaderPageContent'; import { TechDocsReaderPageSubheader } from './reader/components/TechDocsReaderPageSubheader'; +import { useEntityPageTechDocsRedirect } from './search/hooks/useTechDocsLocation'; -type EntityPageDocsProps = { entity: Entity }; +type EntityPageDocsProps = { + entity: Entity; + /** + * Show or hide the content search bar, defaults to true. + */ + withSearch?: boolean; +}; -export const EntityPageDocs = ({ entity }: EntityPageDocsProps) => { +export const EntityPageDocs = ({ + entity, + withSearch = true, +}: EntityPageDocsProps) => { let entityRef = getCompoundEntityRef(entity); + const searchResultUrlMapper = useEntityPageTechDocsRedirect(entityRef); + if (entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) { try { entityRef = parseEntityRef( @@ -44,7 +56,10 @@ export const EntityPageDocs = ({ entity }: EntityPageDocsProps) => { return ( - + ); }; diff --git a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx index 2fbd5bb50a..f9757f29cc 100644 --- a/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx +++ b/plugins/techdocs/src/home/components/DefaultTechDocsHome.tsx @@ -46,7 +46,13 @@ export type DefaultTechDocsHomeProps = TechDocsIndexPageProps; * @public */ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => { - const { initialFilter = 'owned', columns, actions, ownerPickerMode } = props; + const { + initialFilter = 'owned', + columns, + actions, + ownerPickerMode, + pagination, + } = props; return ( @@ -55,7 +61,7 @@ export const DefaultTechDocsHome = (props: TechDocsIndexPageProps) => { Discover documentation in your ecosystem. - + diff --git a/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx new file mode 100644 index 0000000000..d7ab3827e1 --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.test.tsx @@ -0,0 +1,168 @@ +/* + * 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 React, { ReactNode } from 'react'; +import { fireEvent, screen, waitFor } from '@testing-library/react'; +import { CursorPaginatedDocsTable } from './CursorPaginatedDocsTable'; +import { DocsTableRow } from './types'; +import { renderInTestApp } from '@backstage/test-utils'; +import { + DefaultEntityFilters, + EntityKindFilter, + EntityListContextProps, +} from '@backstage/plugin-catalog-react'; +import { MockEntityListContextProvider } from '@backstage/plugin-catalog-react/testUtils'; + +describe('CursorPaginatedDocsTable', () => { + const data = new Array(100).fill(0).map((_, index) => { + const name = `techdocs-${index}`; + return { + entity: { + apiVersion: '1', + kind: 'TestKind', + metadata: { + name, + }, + }, + resolved: { + docsUrl: 'https://example.com', + ownedByRelationsTitle: 'owned', + ownedByRelations: [], + }, + } as DocsTableRow; + }); + + const columns = [ + { + title: 'Title', + field: 'entity.metadata.name', + searchable: true, + }, + ]; + + const wrapInContext = ( + node: ReactNode, + value?: Partial>, + ) => { + return ( + + {node} + + ); + }; + + it('should display all the items', async () => { + await renderInTestApp( + wrapInContext(), + ); + + for (const item of data) { + expect(screen.queryByText(item.entity.metadata.name)).toBeInTheDocument(); + } + }); + + it('should display and invoke the next button', async () => { + const { rerender } = await renderInTestApp( + wrapInContext( + , + ), + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender( + wrapInContext( + , + ), + ); + + const nextButton = screen.queryAllByRole('button', { + name: 'Next Page', + })[0]; + expect(nextButton).toBeEnabled(); + + fireEvent.click(nextButton); + expect(fn).toHaveBeenCalled(); + }); + + it('should display and invoke the prev button', async () => { + const { rerender } = await renderInTestApp( + wrapInContext( + , + ), + ); + + expect( + screen.queryAllByRole('button', { name: 'Next Page' })[0], + ).toBeDisabled(); + + const fn = jest.fn(); + + rerender( + wrapInContext( + , + ), + ); + + const prevButton = screen.queryAllByRole('button', { + name: 'Previous Page', + })[0]; + expect(prevButton).toBeEnabled(); + + fireEvent.click(prevButton); + expect(fn).toHaveBeenCalled(); + }); + + it('should display entity names when loading has finished and no error occurred', async () => { + await renderInTestApp( + e.entity), + totalItems: data.length, + filters: { + kind: new EntityKindFilter('techdocs'), + }, + }} + > + + , + ); + + expect(screen.getByText(/techdocs-0/)).toBeInTheDocument(); + expect(screen.getByText(/techdocs-50/)).toBeInTheDocument(); + expect(screen.getByText(/techdocs-99/)).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText(/My title/)).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx new file mode 100644 index 0000000000..48a1ecddce --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/CursorPaginatedDocsTable.tsx @@ -0,0 +1,75 @@ +/* + * 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 React from 'react'; + +import { Table, TableProps } from '@backstage/core-components'; +import { DocsTableRow } from './types'; + +type PaginatedDocsTableProps = { + prev?(): void; + next?(): void; +} & TableProps; + +/** + * @internal + */ + +export function CursorPaginatedDocsTable(props: PaginatedDocsTableProps) { + const { + actions, + columns, + data, + next, + prev, + title, + isLoading, + options, + ...restProps + } = props; + + return ( + { + if (page > 0) { + next?.(); + } else { + prev?.(); + } + }} + /* this will enable the prev button accordingly */ + page={prev ? 1 : 0} + /* this will enable the next button accordingly */ + totalCount={next ? Number.MAX_VALUE : Number.MAX_SAFE_INTEGER} + localization={{ pagination: { labelDisplayedRows: '' } }} + isLoading={isLoading} + {...restProps} + /> + ); +} diff --git a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx index b1537affdb..29dbb3fd4f 100644 --- a/plugins/techdocs/src/home/components/Tables/DocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/DocsTable.tsx @@ -18,11 +18,7 @@ import React from 'react'; import useCopyToClipboard from 'react-use/esm/useCopyToClipboard'; import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; -import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model'; -import { - getEntityRelations, - humanizeEntityRef, -} from '@backstage/plugin-catalog-react'; +import { Entity } from '@backstage/catalog-model'; import { rootDocsRouteRef } from '../../../routes'; import { EmptyState, @@ -33,9 +29,9 @@ import { TableProps, } from '@backstage/core-components'; import { actionFactories } from './actions'; -import { columnFactories } from './columns'; -import { toLowerMaybe } from '../../../helpers'; +import { columnFactories, defaultColumns } from './columns'; import { DocsTableRow } from './types'; +import { entitiesToDocsMapper } from './helpers'; /** * Props for {@link DocsTable}. @@ -51,14 +47,6 @@ export type DocsTableProps = { options?: TableOptions; }; -const defaultColumns: TableColumn[] = [ - columnFactories.createTitleColumn({ hidden: true }), - columnFactories.createNameColumn(), - columnFactories.createOwnerColumn(), - columnFactories.createKindColumn(), - columnFactories.createTypeColumn(), -]; - /** * Component which renders a table documents * @@ -71,26 +59,11 @@ export const DocsTable = (props: DocsTableProps) => { const config = useApi(configApiRef); if (!entities) return null; - const documents = entities.map(entity => { - const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); - return { - entity, - resolved: { - docsUrl: getRouteToReaderPageFor({ - namespace: toLowerMaybe( - entity.metadata.namespace ?? 'default', - config, - ), - kind: toLowerMaybe(entity.kind, config), - name: toLowerMaybe(entity.metadata.name, config), - }), - ownedByRelations, - ownedByRelationsTitle: ownedByRelations - .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) - .join(', '), - }, - }; - }); + const documents = entitiesToDocsMapper( + entities, + getRouteToReaderPageFor, + config, + ); const defaultActions: TableProps['actions'] = [ actionFactories.createCopyDocsUrlAction(copyToClipboard), diff --git a/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx index 563bec4d22..08702d2fde 100644 --- a/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx +++ b/plugins/techdocs/src/home/components/Tables/EntityListDocsTable.tsx @@ -24,14 +24,19 @@ import { TableProps, WarningPanel, } from '@backstage/core-components'; +import { configApiRef, useApi, useRouteRef } from '@backstage/core-plugin-api'; import { useEntityList, useStarredEntities, } from '@backstage/plugin-catalog-react'; import { DocsTable } from './DocsTable'; +import { OffsetPaginatedDocsTable } from './OffsetPaginatedDocsTable'; +import { CursorPaginatedDocsTable } from './CursorPaginatedDocsTable'; import { actionFactories } from './actions'; -import { columnFactories } from './columns'; +import { columnFactories, defaultColumns } from './columns'; import { DocsTableRow } from './types'; +import { rootDocsRouteRef } from '../../../routes'; +import { entitiesToDocsMapper } from './helpers'; /** * Props for {@link EntityListDocsTable}. @@ -51,9 +56,12 @@ export type EntityListDocsTableProps = { */ export const EntityListDocsTable = (props: EntityListDocsTableProps) => { const { columns, actions, options } = props; - const { loading, error, entities, filters } = useEntityList(); + const { loading, error, entities, filters, paginationMode, pageInfo } = + useEntityList(); const { isStarredEntity, toggleStarredEntity } = useStarredEntities(); const [, copyToClipboard] = useCopyToClipboard(); + const getRouteToReaderPageFor = useRouteRef(rootDocsRouteRef); + const config = useApi(configApiRef); const title = capitalize(filters.user?.value ?? 'all'); @@ -65,6 +73,38 @@ export const EntityListDocsTable = (props: EntityListDocsTableProps) => { ), ]; + const documents = entitiesToDocsMapper( + entities, + getRouteToReaderPageFor, + config, + ); + + if (paginationMode === 'cursor') { + return ( + + ); + } else if (paginationMode === 'offset') { + return ( + + ); + } + if (error) { return ( { + const data = new Array(100).fill(0).map((_, index) => { + const name = `tectdocs-${index}`; + return { + entity: { + apiVersion: '1', + kind: 'TestKind', + metadata: { + name, + }, + }, + resolved: { + docsUrl: 'https://example.com', + ownedByRelationsTitle: 'owned', + ownedByRelations: [], + }, + } as DocsTableRow; + }); + + const columns = [ + { + title: 'Title', + field: 'entity.metadata.name', + searchable: true, + }, + ]; + + const wrapInContext = ( + node: ReactNode, + value?: Partial>, + ) => { + return ( + + {node} + + ); + }; + + it('should display all the items', async () => { + await renderInTestApp( + wrapInContext( + , + { + setOffset: jest.fn(), + limit: Number.MAX_SAFE_INTEGER, + offset: 0, + totalItems: data.length, + }, + ), + ); + + for (const item of data) { + expect(screen.queryByText(item.entity.metadata.name)).toBeInTheDocument(); + } + }); + + it('should display and invoke the next and previous buttons', async () => { + const offsetFn = jest.fn(); + + await renderInTestApp( + wrapInContext( + , + { setOffset: offsetFn, limit: 10, totalItems: data.length, offset: 0 }, + ), + ); + + expect(offsetFn).toHaveBeenNthCalledWith(1, 0); + const nextButton = screen.queryAllByRole('button', { + name: 'Next Page', + })[0]; + expect(nextButton).toBeEnabled(); + + fireEvent.click(nextButton); + expect(offsetFn).toHaveBeenNthCalledWith(2, 10); + + const prevButton = screen.queryAllByRole('button', { + name: 'Previous Page', + })[0]; + expect(prevButton).toBeEnabled(); + + fireEvent.click(prevButton); + expect(offsetFn).toHaveBeenNthCalledWith(3, 0); + }); +}); diff --git a/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx b/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx new file mode 100644 index 0000000000..9f4572117d --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/OffsetPaginatedDocsTable.tsx @@ -0,0 +1,75 @@ +/* + * 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 React, { useEffect } from 'react'; + +import { Table, TableProps } from '@backstage/core-components'; +import { DocsTableRow } from './types'; +import { + EntityTextFilter, + useEntityList, +} from '@backstage/plugin-catalog-react'; + +/** + * @internal + */ +export function OffsetPaginatedDocsTable(props: TableProps) { + const { actions, columns, data, isLoading, options } = props; + const { updateFilters, setLimit, setOffset, limit, totalItems, offset } = + useEntityList(); + const [page, setPage] = React.useState( + offset && limit ? Math.floor(offset / limit) : 0, + ); + + useEffect(() => { + if (totalItems && page * limit >= totalItems) { + setOffset!(Math.max(0, totalItems - limit)); + } else { + setOffset!(Math.max(0, page * limit)); + } + }, [setOffset, page, limit, totalItems]); + + return ( + + columns={columns} + data={data} + options={{ + paginationPosition: 'both', + pageSizeOptions: [5, 10, 20, 50, 100], + pageSize: limit, + emptyRowsWhenPaging: false, + actionsColumnIndex: -1, + ...options, + }} + actions={actions} + onSearchChange={(searchText: string) => + updateFilters({ + text: searchText ? new EntityTextFilter(searchText) : undefined, + }) + } + page={page} + onPageChange={newPage => { + setPage(newPage); + }} + onRowsPerPageChange={pageSize => { + setLimit(pageSize); + }} + totalCount={totalItems} + localization={{ pagination: { labelDisplayedRows: '' } }} + isLoading={isLoading} + /> + ); +} diff --git a/plugins/techdocs/src/home/components/Tables/columns.tsx b/plugins/techdocs/src/home/components/Tables/columns.tsx index ef22f6d288..9947e1de9e 100644 --- a/plugins/techdocs/src/home/components/Tables/columns.tsx +++ b/plugins/techdocs/src/home/components/Tables/columns.tsx @@ -85,3 +85,11 @@ export const columnFactories = { }; }, }; + +export const defaultColumns: TableColumn[] = [ + columnFactories.createTitleColumn({ hidden: true }), + columnFactories.createNameColumn(), + columnFactories.createOwnerColumn(), + columnFactories.createKindColumn(), + columnFactories.createTypeColumn(), +]; diff --git a/plugins/techdocs/src/home/components/Tables/helpers.ts b/plugins/techdocs/src/home/components/Tables/helpers.ts new file mode 100644 index 0000000000..4c6383c35e --- /dev/null +++ b/plugins/techdocs/src/home/components/Tables/helpers.ts @@ -0,0 +1,56 @@ +/* + * 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 { RELATION_OWNED_BY, Entity } from '@backstage/catalog-model'; +import { + getEntityRelations, + humanizeEntityRef, +} from '@backstage/plugin-catalog-react'; +import { toLowerMaybe } from '../../../helpers'; +import { ConfigApi, RouteFunc } from '@backstage/core-plugin-api'; + +type getRouteFunc = RouteFunc<{ + namespace: string; + kind: string; + name: string; +}>; + +export function entitiesToDocsMapper( + entities: Entity[], + getRouteToReaderPageFor: getRouteFunc, + config: ConfigApi, +) { + return entities.map(entity => { + const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY); + return { + entity, + resolved: { + docsUrl: getRouteToReaderPageFor({ + namespace: toLowerMaybe( + entity.metadata.namespace ?? 'default', + config, + ), + kind: toLowerMaybe(entity.kind, config), + name: toLowerMaybe(entity.metadata.name, config), + }), + ownedByRelations, + ownedByRelationsTitle: ownedByRelations + .map(r => humanizeEntityRef(r, { defaultKind: 'group' })) + .join(', '), + }, + }; + }); +} diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx index 409d68a593..585248c6c9 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.test.tsx @@ -14,7 +14,11 @@ * limitations under the License. */ -import { catalogApiRef } from '@backstage/plugin-catalog-react'; +import { + catalogApiRef, + starredEntitiesApiRef, + MockStarredEntitiesApi, +} from '@backstage/plugin-catalog-react'; import { catalogApiMock } from '@backstage/plugin-catalog-react/testUtils'; import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils'; import { screen } from '@testing-library/react'; @@ -37,7 +41,10 @@ const mockCatalogApi = catalogApiMock({ }); describe('TechDocsCustomHome', () => { - const apiRegistry = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); + const apiRegistry = TestApiRegistry.from( + [catalogApiRef, mockCatalogApi], + [starredEntitiesApiRef, new MockStarredEntitiesApi()], + ); it('should render a TechDocs home page', async () => { const tabsConfig = [ diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx index 56d086acfc..d89bc5ee1b 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx @@ -23,6 +23,7 @@ import { catalogApiRef, CatalogApi, useEntityOwnership, + EntityListProvider, } from '@backstage/plugin-catalog-react'; import { Entity } from '@backstage/catalog-model'; import { DocsTable } from './Tables'; @@ -127,7 +128,9 @@ const CustomPanel = ({ ) : null}
- + + +
); diff --git a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx index adbb68d3e9..cc89d22c08 100644 --- a/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx +++ b/plugins/techdocs/src/home/components/TechDocsIndexPage.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { useOutlet } from 'react-router-dom'; import { TableColumn, TableProps } from '@backstage/core-components'; import { + EntityListPagination, EntityOwnerPickerProps, UserListFilterKind, } from '@backstage/plugin-catalog-react'; @@ -34,6 +35,7 @@ export type TechDocsIndexPageProps = { columns?: TableColumn[]; actions?: TableProps['actions']; ownerPickerMode?: EntityOwnerPickerProps['mode']; + pagination?: EntityListPagination; }; export const TechDocsIndexPage = (props: TechDocsIndexPageProps) => { diff --git a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx index 21418a716e..f8b3129feb 100644 --- a/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsReaderPageContent/TechDocsReaderPageContent.tsx @@ -64,6 +64,13 @@ export type TechDocsReaderPageContentProps = { * Show or hide the search bar, defaults to true. */ withSearch?: boolean; + /** + * If {@link TechDocsReaderPageContentProps.withSearch | withSearch} is true, + * this will redirect the search result urls, e.g. turn search results into + * links within the "Docs" tab of the entity page, instead of the global docs + * page. + */ + searchResultUrlMapper?: (url: string) => string; /** * Callback called when the content is rendered. */ @@ -76,7 +83,7 @@ export type TechDocsReaderPageContentProps = { */ export const TechDocsReaderPageContent = withTechDocsReaderProvider( (props: TechDocsReaderPageContentProps) => { - const { withSearch = true, onReady } = props; + const { withSearch = true, searchResultUrlMapper, onReady } = props; const classes = useStyles(); const { @@ -142,6 +149,7 @@ export const TechDocsReaderPageContent = withTechDocsReaderProvider( )} diff --git a/plugins/techdocs/src/reader/components/useReaderState.test.tsx b/plugins/techdocs/src/reader/components/useReaderState.test.tsx index 60898ab288..cfa7d76ba1 100644 --- a/plugins/techdocs/src/reader/components/useReaderState.test.tsx +++ b/plugins/techdocs/src/reader/components/useReaderState.test.tsx @@ -687,5 +687,43 @@ describe('useReaderState', () => { expect.any(Function), ); }); + + it('should return the same data if re-rendered', async () => { + techdocsStorageApi.getEntityDocs.mockResolvedValue('my content'); + techdocsStorageApi.syncEntityDocs.mockImplementation(async () => { + return 'cached'; + }); + + const { result, rerender } = renderHook( + () => useReaderState('Component', 'default', 'backstage', '/example'), + { wrapper: Wrapper }, + ); + + expect(result.current).toEqual({ + state: 'CHECKING', + path: '/example', + content: undefined, + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); + + await waitFor(() => { + expect(result.current).toEqual({ + state: 'CONTENT_FRESH', + path: '/example', + content: 'my content', + contentErrorMessage: undefined, + syncErrorMessage: undefined, + buildLog: [], + contentReload: expect.any(Function), + }); + }); + const firstResult = result.current; + + rerender(); + expect(result.current).toBe(firstResult); + }); }); }); diff --git a/plugins/techdocs/src/reader/components/useReaderState.ts b/plugins/techdocs/src/reader/components/useReaderState.ts index 251ae6e3d5..459c6a3728 100644 --- a/plugins/techdocs/src/reader/components/useReaderState.ts +++ b/plugins/techdocs/src/reader/components/useReaderState.ts @@ -343,13 +343,24 @@ export function useReaderState( [state.activeSyncState, state.content, state.contentLoading], ); - return { - state: displayState, - contentReload, - path: state.path, - content: state.content, - contentErrorMessage: state.contentError?.toString(), - syncErrorMessage: state.syncError?.toString(), - buildLog: state.buildLog, - }; + return useMemo( + () => ({ + state: displayState, + contentReload, + path: state.path, + content: state.content, + contentErrorMessage: state.contentError?.toString(), + syncErrorMessage: state.syncError?.toString(), + buildLog: state.buildLog, + }), + [ + displayState, + contentReload, + state.path, + state.content, + state.contentError, + state.syncError, + state.buildLog, + ], + ); } diff --git a/plugins/techdocs/src/search/components/TechDocsSearch.tsx b/plugins/techdocs/src/search/components/TechDocsSearch.tsx index ce77d547db..b283581fa2 100644 --- a/plugins/techdocs/src/search/components/TechDocsSearch.tsx +++ b/plugins/techdocs/src/search/components/TechDocsSearch.tsx @@ -34,6 +34,7 @@ export type TechDocsSearchProps = { entityId: CompoundEntityRef; entityTitle?: string; debounceTime?: number; + searchResultUrlMapper?: (url: string) => string; }; type TechDocsDoc = { @@ -58,7 +59,12 @@ const isTechDocsSearchResult = ( }; const TechDocsSearchBar = (props: TechDocsSearchProps) => { - const { entityId, entityTitle, debounceTime = 150 } = props; + const { + entityId, + entityTitle, + debounceTime = 150, + searchResultUrlMapper, + } = props; const [open, setOpen] = useState(false); const navigate = useNavigate(); const { @@ -102,7 +108,9 @@ const TechDocsSearchBar = (props: TechDocsSearchProps) => { ) => { if (isTechDocsSearchResult(selection)) { const { location } = selection.document; - navigate(location); + navigate( + searchResultUrlMapper ? searchResultUrlMapper(location) : location, + ); } }; diff --git a/plugins/techdocs/src/search/hooks/useTechDocsLocation.ts b/plugins/techdocs/src/search/hooks/useTechDocsLocation.ts new file mode 100644 index 0000000000..737dd2839c --- /dev/null +++ b/plugins/techdocs/src/search/hooks/useTechDocsLocation.ts @@ -0,0 +1,62 @@ +/* + * 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 { useMemo } from 'react'; + +import { CompoundEntityRef } from '@backstage/catalog-model'; +import { useRouteRef } from '@backstage/core-plugin-api'; + +import { rootCatalogDocsRouteRef, rootDocsRouteRef } from '../../routes'; + +const trimStartSlash = (path: string) => path.replace(/^\/+/, ''); +const trimEndSlash = (path: string) => path.replace(/\/+$/, ''); + +/** + * Returns a function that takes a location to a Tech Docs entry, and returns a + * new location, re-routed to the catalog page tab. + * + * @internal + */ +export function useEntityPageTechDocsRedirect(entityRef: CompoundEntityRef) { + const { kind, name, namespace } = entityRef; + + const routeDocsRoot = useRouteRef(rootDocsRouteRef); + const routeDocsCatalog = useRouteRef(rootCatalogDocsRouteRef); + + // Re-routes a /docs/:namespace/:kind/:name/* location into + // /catalog/:namespace/:kind/:name/docs/*, while handling situations where + // these defaults are changed. + // eslint-disable-next-line react-hooks/rules-of-hooks + const reRouteLocationToCatalog = useMemo(() => { + const rootDocsPath = trimEndSlash(routeDocsRoot({ kind, namespace, name })); + const catalogDocsPath = trimEndSlash(routeDocsCatalog()); + + return (url: string): string => { + if ( + url + .toLocaleLowerCase('en-US') + .startsWith(rootDocsPath.toLocaleLowerCase('en-US')) + ) { + const suffix = trimStartSlash(url.slice(rootDocsPath.length)); + return suffix.length === 0 || suffix.startsWith('#') + ? `${catalogDocsPath}${suffix}` + : `${catalogDocsPath}/${suffix}`; + } + return url; + }; + }, [routeDocsRoot, routeDocsCatalog, kind, name, namespace]); + + return reRouteLocationToCatalog; +} diff --git a/plugins/user-settings-backend/CHANGELOG.md b/plugins/user-settings-backend/CHANGELOG.md index 5347502277..43a06fba57 100644 --- a/plugins/user-settings-backend/CHANGELOG.md +++ b/plugins/user-settings-backend/CHANGELOG.md @@ -1,5 +1,61 @@ # @backstage/plugin-user-settings-backend +## 0.2.28-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.2 + - @backstage/backend-plugin-api@1.1.0-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/plugin-auth-node@0.5.5-next.2 + - @backstage/plugin-signals-node@0.1.15-next.2 + - @backstage/config@1.3.1-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.2.28-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-auth-node@0.5.5-next.1 + - @backstage/backend-defaults@0.6.0-next.1 + - @backstage/backend-plugin-api@1.1.0-next.1 + - @backstage/plugin-signals-node@0.1.15-next.1 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.2.28-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/backend-defaults@0.6.0-next.0 + - @backstage/backend-plugin-api@1.0.3-next.0 + - @backstage/plugin-auth-node@0.5.5-next.0 + - @backstage/config@1.3.0 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-node@0.1.15-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.2.27 + +### Patch Changes + +- Updated dependencies + - @backstage/config@1.3.0 + - @backstage/backend-defaults@0.5.3 + - @backstage/types@1.2.0 + - @backstage/plugin-auth-node@0.5.4 + - @backstage/backend-plugin-api@1.0.2 + - @backstage/plugin-signals-node@0.1.14 + - @backstage/errors@1.2.5 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.2.27-next.3 ### Patch Changes diff --git a/plugins/user-settings-backend/package.json b/plugins/user-settings-backend/package.json index dbc7a93ff8..93942be61f 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.2.27-next.3", + "version": "0.2.28-next.2", "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 1973cb0435..90a75362e3 100644 --- a/plugins/user-settings/CHANGELOG.md +++ b/plugins/user-settings/CHANGELOG.md @@ -1,5 +1,77 @@ # @backstage/plugin-user-settings +## 0.8.17-next.2 + +### Patch Changes + +- Updated dependencies + - @backstage/core-compat-api@0.3.4-next.2 + - @backstage/plugin-catalog-react@1.14.3-next.2 + - @backstage/errors@1.2.6-next.0 + - @backstage/catalog-model@1.7.2-next.0 + - @backstage/core-app-api@1.15.3-next.1 + - @backstage/core-components@0.16.2-next.2 + - @backstage/core-plugin-api@1.10.2-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.2 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.8-next.0 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.17-next.1 + +### Patch Changes + +- Updated dependencies + - @backstage/plugin-catalog-react@1.14.3-next.1 + - @backstage/core-components@0.16.2-next.1 + - @backstage/catalog-model@1.7.1 + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/core-compat-api@0.3.4-next.1 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.3-next.1 + - @backstage/theme@0.6.3-next.0 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.17-next.0 + +### Patch Changes + +- Updated dependencies + - @backstage/core-app-api@1.15.3-next.0 + - @backstage/plugin-catalog-react@1.14.3-next.0 + - @backstage/frontend-plugin-api@0.9.3-next.0 + - @backstage/theme@0.6.3-next.0 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.4-next.0 + - @backstage/core-components@0.16.2-next.0 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/types@1.2.0 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + +## 0.8.15 + +### Patch Changes + +- Updated dependencies + - @backstage/theme@0.6.1 + - @backstage/types@1.2.0 + - @backstage/plugin-catalog-react@1.14.1 + - @backstage/core-components@0.16.0 + - @backstage/core-app-api@1.15.2 + - @backstage/catalog-model@1.7.1 + - @backstage/core-compat-api@0.3.2 + - @backstage/core-plugin-api@1.10.1 + - @backstage/errors@1.2.5 + - @backstage/frontend-plugin-api@0.9.1 + - @backstage/plugin-signals-react@0.0.7 + - @backstage/plugin-user-settings-common@0.0.1 + ## 0.8.15-next.3 ### Patch Changes diff --git a/plugins/user-settings/package.json b/plugins/user-settings/package.json index 5af2fe33c0..6aaadd9161 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.15-next.3", + "version": "0.8.17-next.2", "description": "A Backstage plugin that provides a settings page", "backstage": { "role": "frontend-plugin", diff --git a/storybook/yarn.lock b/storybook/yarn.lock index 7acd606734..80d4a3e7fd 100644 --- a/storybook/yarn.lock +++ b/storybook/yarn.lock @@ -2305,13 +2305,13 @@ __metadata: linkType: hard "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" + version: 7.0.5 + resolution: "cross-spawn@npm:7.0.5" dependencies: path-key: ^3.1.0 shebang-command: ^2.0.0 which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + checksum: 55c50004cb6bbea3649784caac6e7b8ddd03fa8c1e14dbd5a1f15896708378006eb7526a52a0f48770c768c9b8aed48a5888eb8e785ff59ff7749e74f66cd96b languageName: node linkType: hard diff --git a/yarn.lock b/yarn.lock index 80274b9284..afc08ad8a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -204,13 +204,13 @@ __metadata: linkType: hard "@apidevtools/json-schema-ref-parser@npm:^11.0.0, @apidevtools/json-schema-ref-parser@npm:^11.7.0": - version: 11.7.2 - resolution: "@apidevtools/json-schema-ref-parser@npm:11.7.2" + version: 11.7.3 + resolution: "@apidevtools/json-schema-ref-parser@npm:11.7.3" dependencies: "@jsdevtools/ono": ^7.1.3 "@types/json-schema": ^7.0.15 js-yaml: ^4.1.0 - checksum: 44096e5cd5a03b17ee5eb0a3b9e9a4db85d87da8ae2abda264eae615f2a43e3e6ba5ca208e1161d4d946755b121c10a9550e88792a725951f2c4cff6df0d8a19 + checksum: 3496edfb2c3d2f9a5a7a49795b4d560f1e4957015aef473775f4b5f2db55a4ddfb3778783401ddd24e7db2930a67a370fb8c68840d8bae0a2a581e0e57fc2f58 languageName: node linkType: hard @@ -297,7 +297,7 @@ __metadata: languageName: node linkType: hard -"@asyncapi/parser@npm:^3.1.0, @asyncapi/parser@npm:^3.3.0": +"@asyncapi/parser@npm:^3.1.0, @asyncapi/parser@npm:^3.3.0, @asyncapi/parser@npm:^3.4.0": version: 3.4.0 resolution: "@asyncapi/parser@npm:3.4.0" dependencies: @@ -324,34 +324,35 @@ __metadata: languageName: node linkType: hard -"@asyncapi/protobuf-schema-parser@npm:^3.2.14": - version: 3.2.14 - resolution: "@asyncapi/protobuf-schema-parser@npm:3.2.14" +"@asyncapi/protobuf-schema-parser@npm:^3.3.0": + version: 3.3.0 + resolution: "@asyncapi/protobuf-schema-parser@npm:3.3.0" dependencies: - "@asyncapi/parser": ^3.1.0 - "@types/protocol-buffers-schema": ^3.4.1 - protobufjs: ^7.2.6 - checksum: b00a50ea806c5e92961d98e51d3c6b61f61377e18f7fe93ccfce5bb47df208c9bdd635b15a6ce3345bb2c33048ed17a1d422b6bd536c8e332c98a29dc1c37ae9 + "@asyncapi/parser": ^3.4.0 + "@types/protocol-buffers-schema": ^3.4.3 + protobufjs: ^7.4.0 + checksum: abe9f09f289c20eb93de450f8106380142ce3aed115060939f90f3826030be56d24759ff3d9c63a2476d22888bb56df5da37222d2eca3e9596f9e0ad6461e93f languageName: node linkType: hard "@asyncapi/react-component@npm:^2.3.3": - version: 2.4.3 - resolution: "@asyncapi/react-component@npm:2.4.3" + version: 2.5.0 + resolution: "@asyncapi/react-component@npm:2.5.0" dependencies: "@asyncapi/avro-schema-parser": ^3.0.24 "@asyncapi/openapi-schema-parser": ^3.0.24 "@asyncapi/parser": ^3.3.0 - "@asyncapi/protobuf-schema-parser": ^3.2.14 + "@asyncapi/protobuf-schema-parser": ^3.3.0 highlight.js: ^10.7.2 isomorphic-dompurify: ^2.14.0 marked: ^4.0.14 openapi-sampler: ^1.2.1 + react-error-boundary: ^4.1.2 use-resize-observer: ^9.1.0 peerDependencies: react: ">=18.0.0" react-dom: ">=18.0.0" - checksum: a302bb0afac4952d77da6558fede68aecedd55096a322ad5b8ca0653aa6e001d21fe681914abea2656c14fb79e1dc6ef8e18ecefce44f877677f0f15fbf6c3c4 + checksum: d975f6182370f43aef9697e3e5b02d93b8ac8b8fcc43a0f8c4315681fdc3b6819078aa6ff963af1193fe7719c2cee78d55a57f188eb472b3e77494a90dbc75e5 languageName: node linkType: hard @@ -1824,8 +1825,8 @@ __metadata: linkType: hard "@azure/storage-blob@npm:^12.5.0": - version: 12.25.0 - resolution: "@azure/storage-blob@npm:12.25.0" + version: 12.26.0 + resolution: "@azure/storage-blob@npm:12.26.0" dependencies: "@azure/abort-controller": ^2.1.2 "@azure/core-auth": ^1.4.0 @@ -1840,7 +1841,7 @@ __metadata: "@azure/logger": ^1.0.0 events: ^3.0.0 tslib: ^2.2.0 - checksum: e592a27d9b8c76654c255544c4b53faea1468bf58f6acb9839115785de46fb6cbd3dce61bb11335af13b932bc651a53eb99140427c7cfcb3f8bd36ecedf38c17 + checksum: c3f7572bc54cd9e74ac73fa9225cc9398a716e574ff9b637e5b27faf4ac2d6207dc64b39f5dcff1671c4cb6730fbd765ebf796abd3e18ef95f5071d613ce3a13 languageName: node linkType: hard @@ -1853,55 +1854,57 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.8.3": - version: 7.24.7 - resolution: "@babel/code-frame@npm:7.24.7" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.16.7, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.8.3": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" dependencies: - "@babel/highlight": ^7.24.7 + "@babel/helper-validator-identifier": ^7.25.9 + js-tokens: ^4.0.0 picocolors: ^1.0.0 - checksum: 830e62cd38775fdf84d612544251ce773d544a8e63df667728cc9e0126eeef14c6ebda79be0f0bc307e8318316b7f58c27ce86702e0a1f5c321d842eb38ffda4 + checksum: db13f5c42d54b76c1480916485e6900748bbcb0014a8aca87f50a091f70ff4e0d0a6db63cade75eb41fcc3d2b6ba0a7f89e343def4f96f00269b41b8ab8dd7b8 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.25.2": - version: 7.25.4 - resolution: "@babel/compat-data@npm:7.25.4" - checksum: b12a91d27c3731a4b0bdc9312a50b1911f41f7f728aaf0d4b32486e2257fd2cb2d3ea1a295e98449600c48f2c7883a3196ca77cda1cef7d97a10c2e83d037974 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9, @babel/compat-data@npm:^7.25.9": + version: 7.26.2 + resolution: "@babel/compat-data@npm:7.26.2" + checksum: d52fae9b0dc59b409d6005ae6b172e89329f46d68136130065ebe923a156fc633e0f1c8600b3e319b9e0f99fd948f64991a5419e2e9431d00d9d235d5f7a7618 languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.19.6, @babel/core@npm:^7.24.7, @babel/core@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/core@npm:7.25.2" +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.18.9, @babel/core@npm:^7.19.6, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.7, @babel/core@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/core@npm:7.26.0" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.24.7 - "@babel/generator": ^7.25.0 - "@babel/helper-compilation-targets": ^7.25.2 - "@babel/helper-module-transforms": ^7.25.2 - "@babel/helpers": ^7.25.0 - "@babel/parser": ^7.25.0 - "@babel/template": ^7.25.0 - "@babel/traverse": ^7.25.2 - "@babel/types": ^7.25.2 + "@babel/code-frame": ^7.26.0 + "@babel/generator": ^7.26.0 + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-module-transforms": ^7.26.0 + "@babel/helpers": ^7.26.0 + "@babel/parser": ^7.26.0 + "@babel/template": ^7.25.9 + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.26.0 convert-source-map: ^2.0.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 json5: ^2.2.3 semver: ^6.3.1 - checksum: 9a1ef604a7eb62195f70f9370cec45472a08114e3934e3eaaedee8fd754edf0730e62347c7b4b5e67d743ce57b5bb8cf3b92459482ca94d06e06246ef021390a + checksum: b296084cfd818bed8079526af93b5dfa0ba70282532d2132caf71d4060ab190ba26d3184832a45accd82c3c54016985a4109ab9118674347a7e5e9bc464894e6 languageName: node linkType: hard -"@babel/generator@npm:^7.25.0, @babel/generator@npm:^7.25.4, @babel/generator@npm:^7.7.2": - version: 7.25.5 - resolution: "@babel/generator@npm:7.25.5" +"@babel/generator@npm:^7.25.9, @babel/generator@npm:^7.26.0, @babel/generator@npm:^7.7.2": + version: 7.26.2 + resolution: "@babel/generator@npm:7.26.2" dependencies: - "@babel/types": ^7.25.4 + "@babel/parser": ^7.26.2 + "@babel/types": ^7.26.0 "@jridgewell/gen-mapping": ^0.3.5 "@jridgewell/trace-mapping": ^0.3.25 - jsesc: ^2.5.1 - checksum: d7713f02536a8144eca810e9b13ae854b05fec462348eaf52e7b50df2c0a312bc43bfff0e8e10d6dd982e8986d61175ac8e67d7358a8b4dad9db4d6733bf0c9c + jsesc: ^3.0.2 + checksum: 6ff850b7d6082619f8c2f518d993cf7254cfbaa20b026282cbef5c9b2197686d076a432b18e36c4d1a42721c016df4f77a8f62c67600775d9683621d534b91b4 languageName: node linkType: hard @@ -1923,16 +1926,16 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.10, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-compilation-targets@npm:7.25.2" +"@babel/helper-compilation-targets@npm:^7.22.10, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-compilation-targets@npm:7.25.9" dependencies: - "@babel/compat-data": ^7.25.2 - "@babel/helper-validator-option": ^7.24.8 - browserslist: ^4.23.1 + "@babel/compat-data": ^7.25.9 + "@babel/helper-validator-option": ^7.25.9 + browserslist: ^4.24.0 lru-cache: ^5.1.1 semver: ^6.3.1 - checksum: aed33c5496cb9db4b5e2d44e26bf8bc474074cc7f7bb5ebe1d4a20fdeb362cb3ba9e1596ca18c7484bcd6e5c3a155ab975e420d520c0ae60df81f9de04d0fd16 + checksum: 3af536e2db358b38f968abdf7d512d425d1018fef2f485d6f131a57a7bcaed32c606b4e148bb230e1508fa42b5b2ac281855a68eb78270f54698c48a83201b9b languageName: node linkType: hard @@ -2019,27 +2022,26 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.5, @babel/helper-module-imports@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-module-imports@npm:7.24.7" +"@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.5, @babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" dependencies: - "@babel/traverse": ^7.24.7 - "@babel/types": ^7.24.7 - checksum: 8ac15d96d262b8940bc469052a048e06430bba1296369be695fabdf6799f201dd0b00151762b56012a218464e706bc033f27c07f6cec20c6f8f5fd6543c67054 + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 1b411ce4ca825422ef7065dffae7d8acef52023e51ad096351e3e2c05837e9bf9fca2af9ca7f28dc26d596a588863d0fedd40711a88e350b736c619a80e704e6 languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.2": - version: 7.25.2 - resolution: "@babel/helper-module-transforms@npm:7.25.2" +"@babel/helper-module-transforms@npm:^7.22.5, @babel/helper-module-transforms@npm:^7.22.9, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" dependencies: - "@babel/helper-module-imports": ^7.24.7 - "@babel/helper-simple-access": ^7.24.7 - "@babel/helper-validator-identifier": ^7.24.7 - "@babel/traverse": ^7.25.2 + "@babel/helper-module-imports": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + "@babel/traverse": ^7.25.9 peerDependencies: "@babel/core": ^7.0.0 - checksum: 282d4e3308df6746289e46e9c39a0870819630af5f84d632559171e4fae6045684d771a65f62df3d569e88ccf81dc2def78b8338a449ae3a94bb421aa14fc367 + checksum: 942eee3adf2b387443c247a2c190c17c4fd45ba92a23087abab4c804f40541790d51ad5277e4b5b1ed8d5ba5b62de73857446b7742f835c18ebd350384e63917 languageName: node linkType: hard @@ -2052,10 +2054,10 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.8 - resolution: "@babel/helper-plugin-utils@npm:7.24.8" - checksum: 73b1a83ba8bcee21dc94de2eb7323207391715e4369fd55844bb15cf13e3df6f3d13a40786d990e6370bf0f571d94fc31f70dec96c1d1002058258c35ca3767a +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.25.9 + resolution: "@babel/helper-plugin-utils@npm:7.25.9" + checksum: e19ec8acf0b696756e6d84531f532c5fe508dce57aa68c75572a77798bd04587a844a9a6c8ea7d62d673e21fdc174d091c9097fb29aea1c1b49f9c6eaa80f022 languageName: node linkType: hard @@ -2114,24 +2116,24 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-string-parser@npm:7.24.8" - checksum: 39b03c5119216883878655b149148dc4d2e284791e969b19467a9411fccaa33f7a713add98f4db5ed519535f70ad273cdadfd2eb54d47ebbdeac5083351328ce +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 6435ee0849e101681c1849868278b5aee82686ba2c1e27280e5e8aca6233af6810d39f8e4e693d2f2a44a3728a6ccfd66f72d71826a94105b86b731697cdfa99 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-validator-identifier@npm:7.24.7" - checksum: 6799ab117cefc0ecd35cd0b40ead320c621a298ecac88686a14cffceaac89d80cdb3c178f969861bf5fa5e4f766648f9161ea0752ecfe080d8e89e3147270257 +"@babel/helper-validator-identifier@npm:^7.22.5, @babel/helper-validator-identifier@npm:^7.24.7, @babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 5b85918cb1a92a7f3f508ea02699e8d2422fe17ea8e82acd445006c0ef7520fbf48e3dbcdaf7b0a1d571fc3a2715a29719e5226636cb6042e15fe6ed2a590944 languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.22.5, @babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-validator-option@npm:7.24.8" - checksum: a52442dfa74be6719c0608fee3225bd0493c4057459f3014681ea1a4643cd38b68ff477fe867c4b356da7330d085f247f0724d300582fa4ab9a02efaf34d107c +"@babel/helper-validator-option@npm:^7.22.5, @babel/helper-validator-option@npm:^7.24.7, @babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d languageName: node linkType: hard @@ -2146,17 +2148,17 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.25.0": - version: 7.25.0 - resolution: "@babel/helpers@npm:7.25.0" +"@babel/helpers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helpers@npm:7.26.0" dependencies: - "@babel/template": ^7.25.0 - "@babel/types": ^7.25.0 - checksum: 739e3704ff41a30f5eaac469b553f4d3ab02be6ced083f5925851532dfbd9efc5c347728e77b754ed0b262a4e5e384e60932a62c192d338db7e4b7f3adf9f4a7 + "@babel/template": ^7.25.9 + "@babel/types": ^7.26.0 + checksum: d77fe8d45033d6007eadfa440355c1355eed57902d5a302f450827ad3d530343430a21210584d32eef2f216ae463d4591184c6fc60cf205bbf3a884561469200 languageName: node linkType: hard -"@babel/highlight@npm:^7.0.0, @babel/highlight@npm:^7.24.7": +"@babel/highlight@npm:^7.0.0": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" dependencies: @@ -2168,14 +2170,14 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.4": - version: 7.25.4 - resolution: "@babel/parser@npm:7.25.4" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/parser@npm:7.26.2" dependencies: - "@babel/types": ^7.25.4 + "@babel/types": ^7.26.0 bin: parser: ./bin/babel-parser.js - checksum: fe4f083d4ad34f019dd7fad672cd007003004fb0a3df9b7315a5da9a5e8e56c1fed95acab6862e7d76cfccb2e8e364bcc307e9117718e6bb6dfb2e87ad065abf + checksum: c88b5ea0adf357ef909cdc2c31e284a154943edc59f63f6e8a4c20bf773a1b2f3d8c2205e59c09ca7cdad91e7466300114548876529277a80651b6436a48d5d9 languageName: node linkType: hard @@ -2432,14 +2434,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.25.4 - resolution: "@babel/plugin-syntax-typescript@npm:7.25.4" +"@babel/plugin-syntax-typescript@npm:^7.23.3, @babel/plugin-syntax-typescript@npm:^7.24.7, @babel/plugin-syntax-typescript@npm:^7.7.2": + version: 7.25.9 + resolution: "@babel/plugin-syntax-typescript@npm:7.25.9" dependencies: - "@babel/helper-plugin-utils": ^7.24.8 + "@babel/helper-plugin-utils": ^7.25.9 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9b89b8930cd5983f64251d75c9fcdc17a8dc73837d6de12220ff972888ecff4054a6467cf0c423cad242aa96c0f0564a39a0823073728cc02239b80d13f02230 + checksum: 0e9821e8ba7d660c36c919654e4144a70546942ae184e85b8102f2322451eae102cbfadbcadd52ce077a2b44b400ee52394c616feab7b5b9f791b910e933fd33 languageName: node linkType: hard @@ -2954,25 +2956,25 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-self@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-react-jsx-self@npm:7.24.7" +"@babel/plugin-transform-react-jsx-self@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-jsx-self@npm:7.25.9" dependencies: - "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-plugin-utils": ^7.25.9 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2d72c33664e614031b8a03fc2d4cfd185e99efb1d681cbde4b0b4ab379864b31d83ee923509892f6d94b2c5893c309f0217d33bcda3e470ed42297f958138381 + checksum: 41c833cd7f91b1432710f91b1325706e57979b2e8da44e83d86312c78bbe96cd9ef778b4e79e4e17ab25fa32c72b909f2be7f28e876779ede28e27506c41f4ae languageName: node linkType: hard -"@babel/plugin-transform-react-jsx-source@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-react-jsx-source@npm:7.24.7" +"@babel/plugin-transform-react-jsx-source@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-react-jsx-source@npm:7.25.9" dependencies: - "@babel/helper-plugin-utils": ^7.24.7 + "@babel/helper-plugin-utils": ^7.25.9 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: c9afcb2259dd124a2de76f8a578589c18bd2f24dbcf78fe02b53c5cbc20c493c4618369604720e4e699b52be10ba0751b97140e1ef8bc8f0de0a935280e9d5b7 + checksum: a3e0e5672e344e9d01fb20b504fe29a84918eaa70cec512c4d4b1b035f72803261257343d8e93673365b72c371f35cf34bb0d129720bf178a4c87812c8b9c662 languageName: node linkType: hard @@ -3323,49 +3325,48 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": - version: 7.24.4 - resolution: "@babel/runtime@npm:7.24.4" +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.18.6, @babel/runtime@npm:^7.20.13, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.25.6, @babel/runtime@npm:^7.26.0, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.4.4, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.6.0, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.3, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.8.7, @babel/runtime@npm:^7.9.2": + version: 7.26.0 + resolution: "@babel/runtime@npm:7.26.0" dependencies: regenerator-runtime: ^0.14.0 - checksum: 2f27d4c0ffac7ae7999ac0385e1106f2a06992a8bdcbf3da06adcac7413863cd08c198c2e4e970041bbea849e17f02e1df18875539b6afba76c781b6b59a07c3 + checksum: c8e2c0504ab271b3467a261a8f119bf2603eb857a0d71e37791f4e3fae00f681365073cc79f141ddaa90c6077c60ba56448004ad5429d07ac73532be9f7cf28a languageName: node linkType: hard -"@babel/template@npm:^7.22.5, @babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0, @babel/template@npm:^7.3.3": - version: 7.25.0 - resolution: "@babel/template@npm:7.25.0" +"@babel/template@npm:^7.22.5, @babel/template@npm:^7.24.7, @babel/template@npm:^7.25.9, @babel/template@npm:^7.3.3": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" dependencies: - "@babel/code-frame": ^7.24.7 - "@babel/parser": ^7.25.0 - "@babel/types": ^7.25.0 - checksum: 3f2db568718756d0daf2a16927b78f00c425046b654cd30b450006f2e84bdccaf0cbe6dc04994aa1f5f6a4398da2f11f3640a4d3ee31722e43539c4c919c817b + "@babel/code-frame": ^7.25.9 + "@babel/parser": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 103641fea19c7f4e82dc913aa6b6ac157112a96d7c724d513288f538b84bae04fb87b1f1e495ac1736367b1bc30e10f058b30208fb25f66038e1f1eb4e426472 languageName: node linkType: hard -"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.4.5": - version: 7.25.4 - resolution: "@babel/traverse@npm:7.25.4" +"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.4, @babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.4.5": + version: 7.25.9 + resolution: "@babel/traverse@npm:7.25.9" dependencies: - "@babel/code-frame": ^7.24.7 - "@babel/generator": ^7.25.4 - "@babel/parser": ^7.25.4 - "@babel/template": ^7.25.0 - "@babel/types": ^7.25.4 + "@babel/code-frame": ^7.25.9 + "@babel/generator": ^7.25.9 + "@babel/parser": ^7.25.9 + "@babel/template": ^7.25.9 + "@babel/types": ^7.25.9 debug: ^4.3.1 globals: ^11.1.0 - checksum: 3b6d879b9d843b119501585269b3599f047011ae21eb7820d00aef62fc3a2bcdaf6f4cdf2679795a2d7c0b6b5d218974916e422f08dea08613dc42188ef21e4b + checksum: 901d325662ff1dd9bc51de00862e01055fa6bc374f5297d7e3731f2f0e268bbb1d2141f53fa82860aa308ee44afdcf186a948f16c83153927925804b95a9594d languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.4, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.25.4 - resolution: "@babel/types@npm:7.25.4" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.5, @babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.26.0 + resolution: "@babel/types@npm:7.26.0" dependencies: - "@babel/helper-string-parser": ^7.24.8 - "@babel/helper-validator-identifier": ^7.24.7 - to-fast-properties: ^2.0.0 - checksum: 497f8b583c54a92a59c3ec542144695064cd5c384fcca46ba1aa301d5e5dd6c1d011f312ca024cb0f9c956da07ae82fb4c348c31a30afa31a074c027720d2aa8 + "@babel/helper-string-parser": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + checksum: a3dd37dabac693018872da96edb8c1843a605c1bfacde6c3f504fba79b972426a6f24df70aa646356c0c1b19bdd2c722c623c684a996c002381071680602280d languageName: node linkType: hard @@ -3470,8 +3471,6 @@ __metadata: compression: ^1.7.4 cookie: ^0.7.0 cors: ^2.8.5 - express: ^4.17.1 - express-promise-router: ^4.1.0 helmet: ^6.0.0 http-errors: ^2.0.0 jose: ^5.0.0 @@ -3483,7 +3482,6 @@ __metadata: minimist: ^1.2.5 morgan: ^1.10.0 msw: ^1.0.0 - node-fetch: ^2.7.0 node-forge: ^1.3.1 path-to-regexp: ^8.0.0 selfsigned: ^2.0.0 @@ -3583,8 +3581,9 @@ __metadata: "@aws-sdk/credential-providers": ^3.350.0 "@aws-sdk/types": ^3.347.0 "@aws-sdk/util-stream-node": ^3.350.0 + "@azure/identity": ^4.0.0 + "@azure/storage-blob": ^12.5.0 "@backstage/backend-app-api": "workspace:^" - "@backstage/backend-common": ^0.25.0 "@backstage/backend-dev-utils": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" @@ -3600,19 +3599,19 @@ __metadata: "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" "@backstage/types": "workspace:^" + "@google-cloud/cloud-sql-connector": ^1.4.0 "@google-cloud/storage": ^7.0.0 - "@keyv/memcache": ^1.3.5 - "@keyv/redis": ^2.5.3 + "@keyv/memcache": ^2.0.1 + "@keyv/redis": ^4.0.1 "@manypkg/get-packages": ^1.1.3 "@octokit/rest": ^19.0.3 - "@opentelemetry/api": ^1.3.0 + "@opentelemetry/api": ^1.9.0 "@types/archiver": ^6.0.0 "@types/base64-stream": ^1.0.2 "@types/concat-stream": ^2.0.0 "@types/cors": ^2.8.6 "@types/express": ^4.17.6 "@types/http-errors": ^2.0.0 - "@types/morgan": ^1.9.0 "@types/node-forge": ^1.3.0 "@types/pg-format": ^1.0.5 "@types/stoppable": ^1.1.0 @@ -3634,26 +3633,26 @@ __metadata: http-errors: ^2.0.0 isomorphic-git: ^1.23.0 jose: ^5.0.0 - keyv: ^4.5.2 + keyv: ^5.2.1 knex: ^3.0.0 lodash: ^4.17.21 logform: ^2.3.2 luxon: ^3.0.0 minimatch: ^9.0.0 minimist: ^1.2.5 - morgan: ^1.10.0 msw: ^1.0.0 mysql2: ^3.0.0 node-fetch: ^2.7.0 node-forge: ^1.3.1 + node-mocks-http: ^1.0.0 p-limit: ^3.1.0 + p-throttle: ^4.1.1 path-to-regexp: ^8.0.0 pg: ^8.11.3 pg-connection-string: ^2.3.0 pg-format: ^1.0.4 raw-body: ^2.4.1 selfsigned: ^2.0.0 - stoppable: ^1.1.0 supertest: ^7.0.0 tar: ^6.1.12 triple-beam: ^1.4.1 @@ -3664,6 +3663,11 @@ __metadata: yauzl: ^3.0.0 yn: ^4.0.0 zod: ^3.22.4 + peerDependencies: + "@google-cloud/cloud-sql-connector": ^1.4.0 + peerDependenciesMeta: + "@google-cloud/cloud-sql-connector": + optional: true languageName: unknown linkType: soft @@ -3741,22 +3745,22 @@ __metadata: languageName: unknown linkType: soft -"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.0.1": - version: 1.0.1 - resolution: "@backstage/backend-plugin-api@npm:1.0.1" +"@backstage/backend-plugin-api@npm:^1.0.0, @backstage/backend-plugin-api@npm:^1.0.2": + version: 1.0.2 + resolution: "@backstage/backend-plugin-api@npm:1.0.2" dependencies: - "@backstage/cli-common": ^0.1.14 - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - "@backstage/plugin-auth-node": ^0.5.3 - "@backstage/plugin-permission-common": ^0.8.1 - "@backstage/types": ^1.1.1 + "@backstage/cli-common": ^0.1.15 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/plugin-auth-node": ^0.5.4 + "@backstage/plugin-permission-common": ^0.8.2 + "@backstage/types": ^1.2.0 "@types/express": ^4.17.6 "@types/luxon": ^3.0.0 express: ^4.17.1 knex: ^3.0.0 luxon: ^3.0.0 - checksum: a0d1dce15c1c90eec64e4f8d7d2eddd4ab43ebf4573db041b1ee835f27939e97eb162c20661fbafb3e8bc223c422512eea1a0327700164e51e328d620ca925c8 + checksum: c74ff15e54ddf31608551875b8b3c41d606ed889908b47baf167e76cf1a8cdd13b1697b8d3e12396e8ae538c7ef879b96a2e13c1bb5011c0bf1ac23719e7795c languageName: node linkType: hard @@ -3774,7 +3778,6 @@ __metadata: "@backstage/types": "workspace:^" "@types/express": ^4.17.6 "@types/luxon": ^3.0.0 - express: ^4.17.1 knex: ^3.0.0 luxon: ^3.0.0 languageName: unknown @@ -3793,8 +3796,8 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-events-node": "workspace:^" "@backstage/types": "workspace:^" - "@keyv/memcache": ^1.3.5 - "@keyv/redis": ^2.5.3 + "@keyv/memcache": ^2.0.1 + "@keyv/redis": ^4.0.1 "@types/express": ^4.17.6 "@types/express-serve-static-core": ^4.17.5 "@types/keyv": ^4.2.0 @@ -3804,7 +3807,7 @@ __metadata: cookie: ^0.7.0 express: ^4.17.1 fs-extra: ^11.0.0 - keyv: ^4.5.2 + keyv: ^5.2.1 knex: ^3.0.0 mysql2: ^3.0.0 pg: ^8.11.3 @@ -3819,15 +3822,57 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-client@npm:^1.7.1": - version: 1.7.1 - resolution: "@backstage/catalog-client@npm:1.7.1" +"@backstage/canon@workspace:packages/canon": + version: 0.0.0-use.local + resolution: "@backstage/canon@workspace:packages/canon" dependencies: - "@backstage/catalog-model": ^1.7.0 - "@backstage/errors": ^1.2.4 + "@backstage/cli": "workspace:^" + "@base_ui/react": ^1.0.0-alpha.3 + "@chromatic-com/storybook": ^3.2.2 + "@remixicon/react": ^4.5.0 + "@storybook/addon-essentials": ^8.4.6 + "@storybook/addon-interactions": ^8.4.6 + "@storybook/addon-styling-webpack": ^1.0.1 + "@storybook/addon-themes": ^8.4.6 + "@storybook/addon-webpack5-compiler-swc": ^1.0.5 + "@storybook/blocks": ^8.4.6 + "@storybook/react": ^8.4.6 + "@storybook/react-webpack5": ^8.4.6 + "@storybook/test": ^8.4.6 + "@testing-library/jest-dom": ^6.0.0 + "@types/react": ^18.0.0 + "@types/react-dom": ^18.0.0 + "@vanilla-extract/rollup-plugin": ^1.3.10 + "@vanilla-extract/sprinkles": ^1.6.3 + "@vanilla-extract/webpack-plugin": ^2.3.14 + eslint-plugin-storybook: ^0.11.1 + globals: ^15.11.0 + mini-css-extract-plugin: ^2.9.2 + react: ^18.0.2 + react-dom: ^18.0.2 + react-router-dom: ^6.3.0 + storybook: ^8.4.6 + webpack-merge: ^6.0.1 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + languageName: unknown + linkType: soft + +"@backstage/catalog-client@npm:^1.8.0": + version: 1.8.0 + resolution: "@backstage/catalog-client@npm:1.8.0" + dependencies: + "@backstage/catalog-model": ^1.7.1 + "@backstage/errors": ^1.2.5 cross-fetch: ^4.0.0 uri-template: ^2.0.0 - checksum: 0a70a929e95b4e424b021010202e19b68ab5ad3a6b6613e5c01850f31f6067e33ebb8863119c197bc213e9d86793d5368d0ad100288802e72eb6e818f54e765f + checksum: 781ce437855eb59cf33687866b64d374471ed9376cdaec9aa4f5dc389ee2a5eb41e98707c902312cc4b99dfc885daa7e26d59228cf6eb5b539c9207aeda02f8c languageName: node linkType: hard @@ -3844,7 +3889,19 @@ __metadata: languageName: unknown linkType: soft -"@backstage/catalog-model@^1.4.3, @backstage/catalog-model@^1.7.0, @backstage/catalog-model@workspace:^, @backstage/catalog-model@workspace:packages/catalog-model": +"@backstage/catalog-model@npm:^1.4.3, @backstage/catalog-model@npm:^1.7.0, @backstage/catalog-model@npm:^1.7.1": + version: 1.7.1 + resolution: "@backstage/catalog-model@npm:1.7.1" + dependencies: + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 + ajv: ^8.10.0 + lodash: ^4.17.21 + checksum: 05e2b386aac897f8ac87c1e479101f8da90d96c517c837b99796a4118cce63932ffbb29fbb1f8ec156258370ff5bab65555bbe2fd7091be438f8c554f0a5bdff + languageName: node + linkType: hard + +"@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: @@ -3859,14 +3916,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/cli-common@npm:^0.1.14": - version: 0.1.14 - resolution: "@backstage/cli-common@npm:0.1.14" - checksum: 6c5031ae31f08b405e5e59105d98e43dc6d865f960e5d016067267ecabccd5a892ab65d59d5b9e31850dccddb9eb29e06bf360ab6be8f7949991561ddb163fcb - languageName: node - linkType: hard - -"@backstage/cli-common@workspace:^, @backstage/cli-common@workspace:packages/cli-common": +"@backstage/cli-common@^0.1.14, @backstage/cli-common@^0.1.15, @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: @@ -3883,6 +3933,7 @@ __metadata: "@backstage/cli": "workspace:^" "@backstage/cli-common": "workspace:^" "@backstage/errors": "workspace:^" + "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 "@yarnpkg/parsers": ^3.0.0 @@ -3921,7 +3972,7 @@ __metadata: "@backstage/theme": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 - "@module-federation/enhanced": ^0.7.0 + "@module-federation/enhanced": ^0.8.0 "@octokit/graphql": ^5.0.0 "@octokit/graphql-schema": ^13.7.0 "@octokit/oauth-app": ^4.2.0 @@ -3976,7 +4027,7 @@ __metadata: commander: ^12.0.0 cross-fetch: ^4.0.0 cross-spawn: ^7.0.3 - css-loader: ^7.0.0 + css-loader: ^6.5.1 ctrlc-windows: ^2.1.0 del: ^8.0.0 esbuild: ^0.24.0 @@ -4000,7 +4051,7 @@ __metadata: global-agent: ^3.0.0 globby: ^11.1.0 handlebars: ^4.7.3 - html-webpack-plugin: ^5.3.1 + html-webpack-plugin: ^5.6.3 inquirer: ^8.2.0 jest: ^29.7.0 jest-cli: ^29.7.0 @@ -4012,7 +4063,6 @@ __metadata: mini-css-extract-plugin: ^2.4.2 minimatch: ^9.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 node-libs-browser: ^2.2.1 nodemon: ^3.0.1 npm-packlist: ^5.0.0 @@ -4027,7 +4077,7 @@ __metadata: react-refresh: ^0.14.0 recursive-readdir: ^2.2.2 replace-in-file: ^7.1.0 - rollup: ^4.0.0 + rollup: ^4.27.3 rollup-plugin-dts: ^6.1.0 rollup-plugin-esbuild: ^6.1.1 rollup-plugin-postcss: ^4.0.0 @@ -4099,13 +4149,13 @@ __metadata: linkType: soft "@backstage/config-loader@npm:^1.9.1": - version: 1.9.1 - resolution: "@backstage/config-loader@npm:1.9.1" + version: 1.9.2 + resolution: "@backstage/config-loader@npm:1.9.2" dependencies: - "@backstage/cli-common": ^0.1.14 - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - "@backstage/types": ^1.1.1 + "@backstage/cli-common": ^0.1.15 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 "@types/json-schema": ^7.0.6 ajv: ^8.10.0 chokidar: ^3.5.2 @@ -4118,7 +4168,7 @@ __metadata: node-fetch: ^2.7.0 typescript-json-schema: ^0.65.0 yaml: ^2.0.0 - checksum: e13ab3cab7a443aa94a5861bf9fe19208bd85a4087f495d6e51d007ff25fcf2c56c26c3682c476422cf407be97dfa6fbe5817595f1f5523a307eae1c23fcc489 + checksum: 92d0be7ccb05879d6a095adca144f3e9a330072282a9fddd1300f908d9292cc8531f248309df687c241b22825d63116e1b56f334cfac399e9b93dca22fe77e29 languageName: node linkType: hard @@ -4143,14 +4193,24 @@ __metadata: lodash: ^4.17.21 minimist: ^1.2.5 msw: ^1.0.0 - node-fetch: ^2.7.0 typescript-json-schema: ^0.65.0 yaml: ^2.0.0 zen-observable: ^0.10.0 languageName: unknown linkType: soft -"@backstage/config@^1.1.1, @backstage/config@^1.2.0, @backstage/config@workspace:^, @backstage/config@workspace:packages/config": +"@backstage/config@npm:^1.1.1, @backstage/config@npm:^1.2.0, @backstage/config@npm:^1.3.0": + version: 1.3.0 + resolution: "@backstage/config@npm:1.3.0" + dependencies: + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 + ms: ^2.1.3 + checksum: 8e117d677889a5170c62f4b867830cded1cddc2f3f52c86fef7df60a974e7f9e38f428d12e30b6dcc038971e736162d52469f6d98917a401f825e544443e0e4e + languageName: node + linkType: hard + +"@backstage/config@workspace:^, @backstage/config@workspace:packages/config": version: 0.0.0-use.local resolution: "@backstage/config@workspace:packages/config" dependencies: @@ -4158,10 +4218,39 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" + ms: ^2.1.3 languageName: unknown linkType: soft -"@backstage/core-app-api@^1.15.1, @backstage/core-app-api@workspace:^, @backstage/core-app-api@workspace:packages/core-app-api": +"@backstage/core-app-api@npm:^1.15.2": + version: 1.15.2 + resolution: "@backstage/core-app-api@npm:1.15.2" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/types": ^1.2.0 + "@backstage/version-bridge": ^1.0.10 + "@types/prop-types": ^15.7.3 + history: ^5.0.0 + i18next: ^22.4.15 + lodash: ^4.17.21 + prop-types: ^15.7.2 + react-use: ^17.2.4 + zen-observable: ^0.10.0 + zod: ^3.22.4 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 7539410665879107bfbe8ae697e9949ba3c697f9ebb63b61a59adb955bee3c35a581cc7d4b16a9c7830adf87081b5968f8ead3719019c3c08f80e2c17840ab0a + languageName: node + linkType: hard + +"@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: @@ -4205,12 +4294,12 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-compat-api@npm:^0.3.1": - version: 0.3.1 - resolution: "@backstage/core-compat-api@npm:0.3.1" +"@backstage/core-compat-api@npm:^0.3.3": + version: 0.3.3 + resolution: "@backstage/core-compat-api@npm:0.3.3" dependencies: - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/frontend-plugin-api": ^0.9.0 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/frontend-plugin-api": ^0.9.2 "@backstage/version-bridge": ^1.0.10 lodash: ^4.17.21 peerDependencies: @@ -4221,7 +4310,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 84fa2896fd85d5c4f2c6c204b6330d92bf928d57a5afc4092c63e952a2417a1257ec914aa7fd22252ea285baeeb55d70611ed95a1748463dd428f8da5fc617aa + checksum: 22b787b80d8e4bfd5ee2da7177fb1c2f64476ee507ab70686a6109ac39fad209896bc3aa09dadf6fb2ad22b0c899202b959d536f70227eebe0598bab1a0a6c50 languageName: node linkType: hard @@ -4241,7 +4330,7 @@ __metadata: "@backstage/test-utils": "workspace:^" "@backstage/types": "workspace:^" "@backstage/version-bridge": "workspace:^" - "@oriflame/backstage-plugin-score-card": ^0.8.0 + "@oriflame/backstage-plugin-score-card": ^0.9.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^16.0.0 "@types/react": ^18.0.0 @@ -4364,6 +4453,59 @@ __metadata: languageName: node linkType: hard +"@backstage/core-components@npm:^0.16.1": + version: 0.16.1 + resolution: "@backstage/core-components@npm:0.16.1" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/errors": ^1.2.5 + "@backstage/theme": ^0.6.2 + "@backstage/version-bridge": ^1.0.10 + "@date-io/core": ^1.3.13 + "@material-table/core": ^3.1.0 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": 4.0.0-alpha.61 + "@react-hookz/web": ^24.0.0 + "@testing-library/react": ^16.0.0 + "@types/react-sparklines": ^1.7.0 + ansi-regex: ^6.0.1 + classnames: ^2.2.6 + d3-selection: ^3.0.0 + d3-shape: ^3.0.0 + d3-zoom: ^3.0.0 + dagre: ^0.8.5 + linkify-react: 4.1.3 + linkifyjs: 4.1.3 + lodash: ^4.17.21 + pluralize: ^8.0.0 + qs: ^6.9.4 + rc-progress: 3.5.1 + react-helmet: 6.1.0 + react-hook-form: ^7.12.2 + react-idle-timer: 5.7.2 + react-markdown: ^8.0.0 + react-sparklines: ^1.7.0 + react-syntax-highlighter: ^15.4.5 + react-use: ^17.3.2 + react-virtualized-auto-sizer: ^1.0.11 + react-window: ^1.8.6 + remark-gfm: ^3.0.1 + zen-observable: ^0.10.0 + zod: ^3.22.4 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 83b5acfa236dc8c6ec7128030b8ef68fbc851c4fd3ccc10bf4b4bb5a95c07606bac845c47dae08ce2a852c0ec2d335e6e8850c7621a57c970dbeb0466b8ee958 + languageName: node + linkType: hard + "@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" @@ -4442,7 +4584,28 @@ __metadata: languageName: unknown linkType: soft -"@backstage/core-plugin-api@^1.10.0, @backstage/core-plugin-api@^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.1, @backstage/core-plugin-api@npm:^1.8.2": + version: 1.10.1 + resolution: "@backstage/core-plugin-api@npm:1.10.1" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 + "@backstage/version-bridge": ^1.0.10 + history: ^5.0.0 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: b9897e92cc595463c11b5719f3d6305debf00dccead6befe04548e7b08c9c03a54c610f64515f443e980c43a6f28e1302ab590d1351bc536d90826f934f336ea + languageName: node + linkType: hard + +"@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: @@ -4490,8 +4653,7 @@ __metadata: fs-extra: ^11.2.0 handlebars: ^4.7.3 inquirer: ^8.2.0 - msw: ^1.0.0 - node-fetch: ^2.7.0 + msw: ^2.0.0 nodemon: ^3.0.1 ora: ^5.3.0 recursive-readdir: ^2.2.2 @@ -4554,7 +4716,17 @@ __metadata: languageName: unknown linkType: soft -"@backstage/errors@^1.2.3, @backstage/errors@^1.2.4, @backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": +"@backstage/errors@npm:^1.2.3, @backstage/errors@npm:^1.2.4, @backstage/errors@npm:^1.2.5": + version: 1.2.5 + resolution: "@backstage/errors@npm:1.2.5" + dependencies: + "@backstage/types": ^1.2.0 + serialize-error: ^8.0.1 + checksum: 8b4411cca1a9038b136ffa766d3ec284d0dac730ef27b1f565dc7f471249ce87a3d6599fe5c21c7643363ee13f0b0457d5c4fa29d20da64ca3a09fecec3ccd31 + languageName: node + linkType: hard + +"@backstage/errors@workspace:^, @backstage/errors@workspace:packages/errors": version: 0.0.0-use.local resolution: "@backstage/errors@workspace:packages/errors" dependencies: @@ -4576,17 +4748,17 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-app-api@npm:^0.10.0": - version: 0.10.0 - resolution: "@backstage/frontend-app-api@npm:0.10.0" +"@backstage/frontend-app-api@npm:^0.10.2": + version: 0.10.2 + resolution: "@backstage/frontend-app-api@npm:0.10.2" dependencies: - "@backstage/config": ^1.2.0 - "@backstage/core-app-api": ^1.15.1 - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/errors": ^1.2.4 - "@backstage/frontend-defaults": ^0.1.1 - "@backstage/frontend-plugin-api": ^0.9.0 - "@backstage/types": ^1.1.1 + "@backstage/config": ^1.3.0 + "@backstage/core-app-api": ^1.15.2 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/errors": ^1.2.5 + "@backstage/frontend-defaults": ^0.1.3 + "@backstage/frontend-plugin-api": ^0.9.2 + "@backstage/types": ^1.2.0 "@backstage/version-bridge": ^1.0.10 lodash: ^4.17.21 zod: ^3.22.4 @@ -4598,7 +4770,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 76728d37614e56d2bf7ee5f6f2d73b57e1c8d8a2aba6d11563645ef1e25db1dfd55910143fda3586b5ef156f3753530b1690b5ac52b8c957e161ab8fae07eb1e + checksum: 7e3485557c7c852a05e0d8567c8b944457c353bafbdd7b21c8cf22a5927c8a18a8a36ec092e9212bad4613f6f0ca7828e9c74ea2b2edc01159c2cffac9d4a0b3 languageName: node linkType: hard @@ -4636,15 +4808,15 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-defaults@npm:^0.1.1": - version: 0.1.1 - resolution: "@backstage/frontend-defaults@npm:0.1.1" +"@backstage/frontend-defaults@npm:^0.1.3": + version: 0.1.3 + resolution: "@backstage/frontend-defaults@npm:0.1.3" dependencies: - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - "@backstage/frontend-app-api": ^0.10.0 - "@backstage/frontend-plugin-api": ^0.9.0 - "@backstage/plugin-app": ^0.1.1 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/frontend-app-api": ^0.10.2 + "@backstage/frontend-plugin-api": ^0.9.2 + "@backstage/plugin-app": ^0.1.3 "@react-hookz/web": ^24.0.0 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 @@ -4654,7 +4826,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 7d74ba5e24726cc322ba2edb1b92c787b6c78ff8a4594ab584631f2cf9232e1de928afd23e49ae04d21501d034acbd99432e5394eeb88798ee520e9d2151b820 + checksum: 46932dad14f776b979ec9482addb8fd1e771b59f690612be2332937fb6d0a9e6d944658f3a5b11d397b773c421ccf6caba0163d10105e2b78ec4a6ecc924d3f5 languageName: node linkType: hard @@ -4688,13 +4860,13 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-plugin-api@npm:^0.9.0": - version: 0.9.0 - resolution: "@backstage/frontend-plugin-api@npm:0.9.0" +"@backstage/frontend-plugin-api@npm:^0.9.2": + version: 0.9.2 + resolution: "@backstage/frontend-plugin-api@npm:0.9.2" dependencies: - "@backstage/core-components": ^0.15.1 - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/types": ^1.1.1 + "@backstage/core-components": ^0.16.1 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/types": ^1.2.0 "@backstage/version-bridge": ^1.0.10 "@material-ui/core": ^4.12.4 lodash: ^4.17.21 @@ -4708,7 +4880,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 12902ce830631878ab1b5ecc22c9b62c4534e45c21b83ff88d8b806a2649ccbfc2fce789764052bc495a3162ed1fae466f6ed6b39aeb3b377da20202dad28fc3 + checksum: 7b24e25ea4178214bdb055faa6dbc62e6be04fe99e89a38a5b79fe9813187d7f6445f798b9c6485a99c8ebb38824677288f133ce73099a3468ddd7c3ec98df26 languageName: node linkType: hard @@ -4746,16 +4918,16 @@ __metadata: languageName: unknown linkType: soft -"@backstage/frontend-test-utils@npm:^0.2.1": - version: 0.2.1 - resolution: "@backstage/frontend-test-utils@npm:0.2.1" +"@backstage/frontend-test-utils@npm:^0.2.3": + version: 0.2.3 + resolution: "@backstage/frontend-test-utils@npm:0.2.3" dependencies: - "@backstage/config": ^1.2.0 - "@backstage/frontend-app-api": ^0.10.0 - "@backstage/frontend-plugin-api": ^0.9.0 - "@backstage/plugin-app": ^0.1.1 - "@backstage/test-utils": ^1.7.0 - "@backstage/types": ^1.1.1 + "@backstage/config": ^1.3.0 + "@backstage/frontend-app-api": ^0.10.2 + "@backstage/frontend-plugin-api": ^0.9.2 + "@backstage/plugin-app": ^0.1.3 + "@backstage/test-utils": ^1.7.2 + "@backstage/types": ^1.2.0 "@backstage/version-bridge": ^1.0.10 zod: ^3.22.4 peerDependencies: @@ -4767,7 +4939,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: eedf49b53b600bbadf98aabc1c8b9082b976eaa3d9c151c9a9eda17ba0ed2e2c2054044d28db95980cf505c14ee8116220a95355a72e71ed22a22e319ef596cb + checksum: 68f6a33b97437f6e3dd7e83e65d44197462a3c8164802bc25a73db5ab3a2726a356f777056cf2700e5702c5a1daa9daca8c0ab4026911159513a2c47c92caf0d languageName: node linkType: hard @@ -4802,17 +4974,17 @@ __metadata: linkType: soft "@backstage/integration-aws-node@npm:^0.1.12": - version: 0.1.12 - resolution: "@backstage/integration-aws-node@npm:0.1.12" + version: 0.1.13 + resolution: "@backstage/integration-aws-node@npm:0.1.13" dependencies: "@aws-sdk/client-sts": ^3.350.0 "@aws-sdk/credential-provider-node": ^3.350.0 "@aws-sdk/credential-providers": ^3.350.0 "@aws-sdk/types": ^3.347.0 "@aws-sdk/util-arn-parser": ^3.310.0 - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - checksum: 01c62b22bdb06eafa174c6f80a95f332df867cebed4554be328efd1f1338dedb86e6bdb7cfda2f2acb1a6a8a92891024da7c81b7ddbfb269b72c3725a54de576 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + checksum: 042617852482685c2452549ad1e16ca319f09e9dc366ad90d7307da6e6763c23ada7bce78e415da9ffef3da7a1287c2ce8c4eddabd1deeaf3f0e7249fdc6e3ee languageName: node linkType: hard @@ -4835,7 +5007,28 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration-react@^1.2.0, @backstage/integration-react@workspace:^, @backstage/integration-react@workspace:packages/integration-react": +"@backstage/integration-react@npm:^1.1.24, @backstage/integration-react@npm:^1.2.1": + version: 1.2.1 + resolution: "@backstage/integration-react@npm:1.2.1" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/integration": ^1.15.2 + "@material-ui/core": ^4.12.2 + "@material-ui/icons": ^4.9.1 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 493e146b2d217ec33ee6f9af39a8289aff230dba548b38d5ec8cff758cfa269184014a18778e54a6599458f408ddc1cab3f2435c229b4f038e9ad423e6086bdb + languageName: node + linkType: hard + +"@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: @@ -4866,11 +5059,29 @@ __metadata: languageName: unknown linkType: soft -"@backstage/integration@^1.15.0, @backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": +"@backstage/integration@npm:^1.15.0, @backstage/integration@npm:^1.15.2, @backstage/integration@npm:^1.9.0": + version: 1.15.2 + resolution: "@backstage/integration@npm:1.15.2" + dependencies: + "@azure/identity": ^4.0.0 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@octokit/auth-app": ^4.0.0 + "@octokit/rest": ^19.0.3 + cross-fetch: ^4.0.0 + git-url-parse: ^15.0.0 + lodash: ^4.17.21 + luxon: ^3.0.0 + checksum: 59b109e1b9e196e36fc55264258a304839057fc1d8f438740c74c1750ee76a5d39341aa4fddaf5d81d06fdc679076710dd63de2fab4e105012eb040d9e303038 + languageName: node + linkType: hard + +"@backstage/integration@workspace:^, @backstage/integration@workspace:packages/integration": version: 0.0.0-use.local resolution: "@backstage/integration@workspace:packages/integration" dependencies: "@azure/identity": ^4.0.0 + "@azure/storage-blob": ^12.5.0 "@backstage/cli": "workspace:^" "@backstage/config": "workspace:^" "@backstage/config-loader": "workspace:^" @@ -4983,7 +5194,6 @@ __metadata: knex: ^3.0.0 lodash: ^4.17.21 luxon: ^3.0.0 - node-fetch: ^2.7.0 supertest: ^7.0.0 yn: ^4.0.0 languageName: unknown @@ -5028,16 +5238,16 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-app@npm:^0.1.1": - version: 0.1.1 - resolution: "@backstage/plugin-app@npm:0.1.1" +"@backstage/plugin-app@npm:^0.1.3": + version: 0.1.3 + resolution: "@backstage/plugin-app@npm:0.1.3" dependencies: - "@backstage/core-components": ^0.15.1 - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/frontend-plugin-api": ^0.9.0 - "@backstage/integration-react": ^1.2.0 - "@backstage/plugin-permission-react": ^0.4.27 - "@backstage/theme": ^0.6.0 + "@backstage/core-components": ^0.16.1 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/frontend-plugin-api": ^0.9.2 + "@backstage/integration-react": ^1.2.1 + "@backstage/plugin-permission-react": ^0.4.28 + "@backstage/theme": ^0.6.2 "@material-ui/core": ^4.9.13 "@material-ui/icons": ^4.9.1 "@material-ui/lab": ^4.0.0-alpha.61 @@ -5050,7 +5260,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: bb75599f8feb8847249a4f5b08aac43be0e61495f16144e4571b3bf9e794c290e0203d73693ae99731c9a4d873cd7ac6ce03a45945b45937834bb1b9eaaa03db + checksum: 9920d4be8e533579de59f43396e1e4ec7bd55fadec58f3e9057401417ec9a126f3df9f4a6fe6c9bcf13e1edb8ded2b9ca41bf871fa3ad21a1b16b5b2a9775731 languageName: node linkType: hard @@ -5141,7 +5351,6 @@ __metadata: jose: ^5.0.0 msw: ^2.0.8 node-cache: ^5.1.2 - node-fetch: ^2.7.0 languageName: unknown linkType: soft @@ -5191,7 +5400,6 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@types/passport-oauth2": ^1.4.15 - node-fetch: ^2.7.0 passport: ^0.7.0 passport-oauth2: ^1.6.1 supertest: ^7.0.0 @@ -5214,7 +5422,6 @@ __metadata: express: ^4.18.2 jose: ^5.0.0 msw: ^2.0.0 - node-fetch: ^2.7.0 node-mocks-http: ^1.0.0 uuid: ^11.0.0 languageName: unknown @@ -5314,7 +5521,6 @@ __metadata: express: ^4.18.2 jose: ^5.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 passport-microsoft: ^1.0.0 supertest: ^7.0.0 languageName: unknown @@ -5514,7 +5720,6 @@ __metadata: morgan: ^1.10.0 msw: ^1.0.0 node-cache: ^5.1.2 - node-fetch: ^2.7.0 openid-client: ^5.2.1 passport: ^0.7.0 passport-auth0: ^1.4.3 @@ -5530,17 +5735,17 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-auth-node@npm:^0.5.2, @backstage/plugin-auth-node@npm:^0.5.3": - version: 0.5.3 - resolution: "@backstage/plugin-auth-node@npm:0.5.3" +"@backstage/plugin-auth-node@npm:^0.5.2, @backstage/plugin-auth-node@npm:^0.5.4": + version: 0.5.4 + resolution: "@backstage/plugin-auth-node@npm:0.5.4" dependencies: "@backstage/backend-common": ^0.25.0 - "@backstage/backend-plugin-api": ^1.0.1 - "@backstage/catalog-client": ^1.7.1 - "@backstage/catalog-model": ^1.7.0 - "@backstage/config": ^1.2.0 - "@backstage/errors": ^1.2.4 - "@backstage/types": ^1.1.1 + "@backstage/backend-plugin-api": ^1.0.2 + "@backstage/catalog-client": ^1.8.0 + "@backstage/catalog-model": ^1.7.1 + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 "@types/express": "*" "@types/passport": ^1.0.3 express: ^4.17.1 @@ -5552,7 +5757,7 @@ __metadata: zod: ^3.22.4 zod-to-json-schema: ^3.21.4 zod-validation-error: ^3.4.0 - checksum: 6a8fcac434b3653011aa634fab973b9bdc9daf141335948669bcbd8e2c5f97e0797feaaaae34e17e20334835cdb83fea6c7b50939f1a18f9c88e245406230c50 + checksum: 3ac80048a7b066e2f05be06412a0205467621cb43a485b3552eb96ec3d90951ec1fac0e066f81fdb30b95c7ddd1d35e920c79138d4c7286bdaf3033d8979ff99 languageName: node linkType: hard @@ -5569,7 +5774,7 @@ __metadata: "@backstage/config": "workspace:^" "@backstage/errors": "workspace:^" "@backstage/types": "workspace:^" - "@types/express": "*" + "@types/express": ^4.17.6 "@types/passport": ^1.0.3 cookie-parser: ^1.4.6 express: ^4.17.1 @@ -5577,7 +5782,6 @@ __metadata: jose: ^5.0.0 lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.7.0 passport: ^0.7.0 supertest: ^7.0.0 uuid: ^11.0.0 @@ -5668,6 +5872,8 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-azure@workspace:plugins/catalog-backend-module-azure" dependencies: + "@azure/identity": ^4.0.0 + "@azure/storage-blob": ^12.5.0 "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" "@backstage/cli": "workspace:^" @@ -5677,7 +5883,6 @@ __metadata: "@backstage/plugin-catalog-node": "workspace:^" luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -5735,10 +5940,9 @@ __metadata: "@backstage/errors": "workspace:^" "@backstage/integration": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" - "@types/node-fetch": ^2.5.12 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 + p-throttle: ^4.1.1 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -5773,7 +5977,6 @@ __metadata: fs-extra: ^11.2.0 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -5816,8 +6019,7 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 minimatch: ^9.0.0 - msw: ^1.0.0 - node-fetch: ^2.7.0 + msw: ^2.0.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -5858,7 +6060,6 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -5867,7 +6068,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-catalog-backend-module-incremental-ingestion@workspace:plugins/catalog-backend-module-incremental-ingestion" dependencies: - "@backstage/backend-common": ^0.25.0 "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" @@ -5880,6 +6080,7 @@ __metadata: "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/types": "workspace:^" + "@opentelemetry/api": ^1.9.0 "@types/express": ^4.17.6 "@types/luxon": ^3.0.0 express: ^4.17.1 @@ -5937,11 +6138,9 @@ __metadata: "@backstage/plugin-catalog-node": "workspace:^" "@microsoft/microsoft-graph-types": ^2.6.0 "@types/lodash": ^4.14.151 - "@types/node-fetch": ^2.5.12 lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 p-limit: ^3.0.2 qs: ^6.9.4 uuid: ^11.0.0 @@ -5986,7 +6185,6 @@ __metadata: lodash: ^4.17.21 luxon: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -6047,7 +6245,7 @@ __metadata: "@backstage/plugin-search-backend-module-catalog": "workspace:^" "@backstage/repo-tools": "workspace:^" "@backstage/types": "workspace:^" - "@opentelemetry/api": ^1.3.0 + "@opentelemetry/api": ^1.9.0 "@types/core-js": ^2.5.4 "@types/express": ^4.17.6 "@types/git-url-parse": ^9.0.0 @@ -6067,7 +6265,6 @@ __metadata: luxon: ^3.0.0 minimatch: ^9.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 p-limit: ^3.0.2 prom-client: ^15.0.0 supertest: ^7.0.0 @@ -6080,7 +6277,18 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-catalog-common@^1.0.20, @backstage/plugin-catalog-common@^1.1.0, @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@npm:^1.1.1": + version: 1.1.1 + resolution: "@backstage/plugin-catalog-common@npm:1.1.1" + dependencies: + "@backstage/catalog-model": ^1.7.1 + "@backstage/plugin-permission-common": ^0.8.2 + "@backstage/plugin-search-common": ^1.2.15 + checksum: de2205ef4ab6ce43dd46d20daed31b9fd5d395b0d78d0e579c7269a5be0741f65ccc690c2346b5945fdb1c5a11a384b9745cdaa495997a179bea9ed55fc5df86 + languageName: node + linkType: hard + +"@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: @@ -6205,22 +6413,22 @@ __metadata: linkType: soft "@backstage/plugin-catalog-react@npm:^1.14.0, @backstage/plugin-catalog-react@npm:^1.9.3": - version: 1.14.0 - resolution: "@backstage/plugin-catalog-react@npm:1.14.0" + version: 1.14.2 + resolution: "@backstage/plugin-catalog-react@npm:1.14.2" dependencies: - "@backstage/catalog-client": ^1.7.1 - "@backstage/catalog-model": ^1.7.0 - "@backstage/core-compat-api": ^0.3.1 - "@backstage/core-components": ^0.15.1 - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/errors": ^1.2.4 - "@backstage/frontend-plugin-api": ^0.9.0 - "@backstage/frontend-test-utils": ^0.2.1 - "@backstage/integration-react": ^1.2.0 - "@backstage/plugin-catalog-common": ^1.1.0 - "@backstage/plugin-permission-common": ^0.8.1 - "@backstage/plugin-permission-react": ^0.4.27 - "@backstage/types": ^1.1.1 + "@backstage/catalog-client": ^1.8.0 + "@backstage/catalog-model": ^1.7.1 + "@backstage/core-compat-api": ^0.3.3 + "@backstage/core-components": ^0.16.1 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/errors": ^1.2.5 + "@backstage/frontend-plugin-api": ^0.9.2 + "@backstage/frontend-test-utils": ^0.2.3 + "@backstage/integration-react": ^1.2.1 + "@backstage/plugin-catalog-common": ^1.1.1 + "@backstage/plugin-permission-common": ^0.8.2 + "@backstage/plugin-permission-react": ^0.4.28 + "@backstage/types": ^1.2.0 "@backstage/version-bridge": ^1.0.10 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 @@ -6241,7 +6449,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: bd358a3be0ed20c2e716b6aec8614884f815362380939d79704f9b667d982a7c5de375693506cec597d5c254cec1426c645ecab891bf81f154c0fda0b6117932 + checksum: 1de29cd4a90fbfa2ba574b6cd69045e15b01e52e2d3963304ab29fc24e00a19d46bd7d3c065ed51ab19bc0ce1bc66e1346d89a3adb034363897b149b3c3dde8e languageName: node linkType: hard @@ -6435,7 +6643,6 @@ __metadata: version: 0.0.0-use.local resolution: "@backstage/plugin-devtools-backend@workspace:plugins/devtools-backend" dependencies: - "@backstage/backend-common": ^0.25.0 "@backstage/backend-defaults": "workspace:^" "@backstage/backend-plugin-api": "workspace:^" "@backstage/backend-test-utils": "workspace:^" @@ -6449,7 +6656,7 @@ __metadata: "@backstage/plugin-permission-node": "workspace:^" "@backstage/types": "workspace:^" "@manypkg/get-packages": ^1.1.3 - "@types/express": "*" + "@types/express": ^4.17.6 "@types/ping": ^0.4.1 "@types/supertest": ^2.0.8 "@types/yarnpkg__lockfile": ^1.1.4 @@ -6459,7 +6666,6 @@ __metadata: express-promise-router: ^4.1.0 fs-extra: ^11.0.0 lodash: ^4.17.21 - node-fetch: ^2.7.0 ping: ^0.4.1 semver: ^7.5.3 supertest: ^7.0.0 @@ -6653,7 +6859,7 @@ __metadata: "@backstage/core-plugin-api": "workspace:^" "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 - "@rjsf/utils": 5.21.2 + "@rjsf/utils": 5.23.1 "@types/react": ^18.0.0 "@types/react-grid-layout": ^1.3.2 react: ^18.0.2 @@ -6691,10 +6897,10 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 - "@rjsf/core": 5.21.2 - "@rjsf/material-ui": 5.21.2 - "@rjsf/utils": 5.21.2 - "@rjsf/validator-ajv8": 5.21.2 + "@rjsf/core": 5.23.1 + "@rjsf/material-ui": 5.23.1 + "@rjsf/utils": 5.23.1 + "@rjsf/validator-ajv8": 5.23.1 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^16.0.0 @@ -6999,7 +7205,6 @@ __metadata: express-promise-router: ^4.1.0 knex: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 supertest: ^7.0.0 uuid: ^11.0.0 winston: ^3.2.1 @@ -7031,7 +7236,6 @@ __metadata: "@backstage/test-utils": "workspace:^" knex: ^3.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 languageName: unknown linkType: soft @@ -7187,7 +7391,7 @@ __metadata: "@backstage/plugin-auth-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" - "@types/express": "*" + "@types/express": ^4.17.6 "@types/lodash": ^4.14.151 "@types/supertest": ^2.0.8 dataloader: ^2.0.0 @@ -7195,14 +7399,28 @@ __metadata: express-promise-router: ^4.1.0 lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.7.0 supertest: ^7.0.0 yn: ^4.0.0 zod: ^3.22.4 languageName: unknown linkType: soft -"@backstage/plugin-permission-common@^0.8.1, @backstage/plugin-permission-common@workspace:^, @backstage/plugin-permission-common@workspace:plugins/permission-common": +"@backstage/plugin-permission-common@npm:^0.8.2": + version: 0.8.2 + resolution: "@backstage/plugin-permission-common@npm:0.8.2" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/errors": ^1.2.5 + "@backstage/types": ^1.2.0 + cross-fetch: ^4.0.0 + uuid: ^11.0.0 + zod: ^3.22.4 + zod-to-json-schema: ^3.20.4 + checksum: f58f205d255c41e39ed331ccb64e807a1ec7728bb7f32c406e52c4d1e4b5e9e2195aa73a1fccbe427c191b0db263f8aa64310dbf5862b4e3834f68a4591de8c3 + languageName: node + linkType: hard + +"@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: @@ -7241,7 +7459,27 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-permission-react@^0.4.27, @backstage/plugin-permission-react@workspace:^, @backstage/plugin-permission-react@workspace:plugins/permission-react": +"@backstage/plugin-permission-react@npm:^0.4.28": + version: 0.4.28 + resolution: "@backstage/plugin-permission-react@npm:0.4.28" + dependencies: + "@backstage/config": ^1.3.0 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/plugin-permission-common": ^0.8.2 + swr: ^2.0.0 + peerDependencies: + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: ad070512472315556cc456c1edb7bcd70be20e352583f4eca7cc1c21d0b75c6d28eb28a47b07cee18594ff554bf4f78f48e034f56c0bbd6fbd1a28b5efe46763 + languageName: node + linkType: hard + +"@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: @@ -7290,7 +7528,6 @@ __metadata: http-proxy-middleware: ^2.0.0 morgan: ^1.10.0 msw: ^2.0.0 - node-fetch: ^2.7.0 uuid: ^11.0.0 winston: ^3.2.1 yaml: ^2.0.0 @@ -7330,7 +7567,6 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7349,7 +7585,6 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7370,7 +7605,6 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" fs-extra: ^11.2.0 msw: ^1.0.0 - node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7391,7 +7625,6 @@ __metadata: fs-extra: ^11.2.0 git-url-parse: ^15.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 node-html-markdown: ^1.3.0 yaml: ^2.0.0 languageName: unknown @@ -7451,7 +7684,6 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" msw: ^1.0.0 - node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7469,7 +7701,6 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" msw: ^1.0.0 - node-fetch: ^2.7.0 yaml: ^2.0.0 languageName: unknown linkType: soft @@ -7514,9 +7745,7 @@ __metadata: "@backstage/integration": "workspace:^" "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" - "@gitbeaker/core": ^35.8.0 - "@gitbeaker/node": ^35.8.0 - "@gitbeaker/rest": ^39.25.0 + "@gitbeaker/rest": ^41.2.0 luxon: ^3.0.0 winston: ^3.2.1 yaml: ^2.0.0 @@ -7576,7 +7805,6 @@ __metadata: "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" "@backstage/types": "workspace:^" msw: ^2.0.0 - node-fetch: ^2.7.0 yaml: ^2.3.3 languageName: unknown linkType: soft @@ -7615,6 +7843,7 @@ __metadata: "@backstage/plugin-bitbucket-cloud-common": "workspace:^" "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" + "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/plugin-permission-node": "workspace:^" "@backstage/plugin-scaffolder-backend-module-azure": "workspace:^" @@ -7629,7 +7858,7 @@ __metadata: "@backstage/plugin-scaffolder-node": "workspace:^" "@backstage/plugin-scaffolder-node-test-utils": "workspace:^" "@backstage/types": "workspace:^" - "@opentelemetry/api": ^1.3.0 + "@opentelemetry/api": ^1.9.0 "@types/express": ^4.17.6 "@types/fs-extra": ^11.0.0 "@types/luxon": ^3.0.0 @@ -7754,10 +7983,10 @@ __metadata: "@material-ui/icons": ^4.9.1 "@material-ui/lab": 4.0.0-alpha.61 "@react-hookz/web": ^24.0.0 - "@rjsf/core": 5.21.2 - "@rjsf/material-ui": 5.21.2 - "@rjsf/utils": 5.21.2 - "@rjsf/validator-ajv8": 5.21.2 + "@rjsf/core": 5.23.1 + "@rjsf/material-ui": 5.23.1 + "@rjsf/utils": 5.23.1 + "@rjsf/validator-ajv8": 5.23.1 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^16.0.0 @@ -7768,7 +7997,7 @@ __metadata: "@types/react": ^18.0.0 ajv-errors: ^3.0.0 classnames: ^2.2.6 - flatted: 3.3.1 + flatted: 3.3.2 humanize-duration: ^3.25.1 json-schema: ^0.4.0 json-schema-library: ^9.0.0 @@ -7828,10 +8057,10 @@ __metadata: "@material-ui/lab": 4.0.0-alpha.61 "@microsoft/fetch-event-source": ^2.0.1 "@react-hookz/web": ^24.0.0 - "@rjsf/core": 5.21.2 - "@rjsf/material-ui": 5.21.2 - "@rjsf/utils": 5.21.2 - "@rjsf/validator-ajv8": 5.21.2 + "@rjsf/core": 5.23.1 + "@rjsf/material-ui": 5.23.1 + "@rjsf/utils": 5.23.1 + "@rjsf/validator-ajv8": 5.23.1 "@testing-library/dom": ^10.0.0 "@testing-library/jest-dom": ^6.0.0 "@testing-library/react": ^16.0.0 @@ -7931,7 +8160,6 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" msw: ^1.2.1 - node-fetch: ^2.7.0 languageName: unknown linkType: soft @@ -7963,7 +8191,6 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-search-common": "workspace:^" msw: ^1.2.1 - node-fetch: ^2.7.0 qs: ^6.9.4 languageName: unknown linkType: soft @@ -7987,7 +8214,6 @@ __metadata: "@backstage/plugin-techdocs-node": "workspace:^" lodash: ^4.17.21 msw: ^1.0.0 - node-fetch: ^2.7.0 p-limit: ^3.1.0 languageName: unknown linkType: soft @@ -8044,6 +8270,16 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-search-common@npm:^1.2.15": + version: 1.2.15 + resolution: "@backstage/plugin-search-common@npm:1.2.15" + dependencies: + "@backstage/plugin-permission-common": ^0.8.2 + "@backstage/types": ^1.2.0 + checksum: 9ea3aafef93074a59127a3e775f82fca1358d330524312c64baaca921baa85e5d80a4042ede050e492ef43c9b6ff9f6eb0a4ea81cb40e09f38834dfc1b57cd57 + languageName: node + linkType: hard + "@backstage/plugin-search-common@workspace:^, @backstage/plugin-search-common@workspace:plugins/search-common": version: 0.0.0-use.local resolution: "@backstage/plugin-search-common@workspace:plugins/search-common" @@ -8084,6 +8320,7 @@ __metadata: react-dom: ^18.0.2 react-router-dom: ^6.3.0 react-use: ^17.3.2 + uuid: ^11.0.2 peerDependencies: "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 react: ^16.13.1 || ^17.0.0 || ^18.0.0 @@ -8154,14 +8391,13 @@ __metadata: "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-signals-node": "workspace:^" "@backstage/types": "workspace:^" - "@types/express": "*" + "@types/express": ^4.17.6 "@types/supertest": ^2.0.8 "@types/ws": ^8.5.10 express: ^4.17.1 express-promise-router: ^4.1.0 http-proxy-middleware: ^2.0.0 msw: ^1.0.0 - node-fetch: ^2.7.0 supertest: ^7.0.0 uuid: ^11.0.0 winston: ^3.2.1 @@ -8310,8 +8546,7 @@ __metadata: fs-extra: ^11.2.0 knex: ^3.0.0 lodash: ^4.17.21 - msw: ^1.0.0 - node-fetch: ^2.7.0 + msw: ^2.0.0 p-limit: ^3.1.0 supertest: ^7.0.0 winston: ^3.2.1 @@ -8580,7 +8815,6 @@ __metadata: dependencies: "@backstage/cli": "workspace:^" "@backstage/test-utils": "workspace:^" - cross-fetch: ^4.0.0 msw: ^1.0.0 languageName: unknown linkType: soft @@ -8646,17 +8880,17 @@ __metadata: languageName: unknown linkType: soft -"@backstage/test-utils@npm:^1.7.0": - version: 1.7.0 - resolution: "@backstage/test-utils@npm:1.7.0" +"@backstage/test-utils@npm:^1.7.2": + version: 1.7.2 + resolution: "@backstage/test-utils@npm:1.7.2" dependencies: - "@backstage/config": ^1.2.0 - "@backstage/core-app-api": ^1.15.1 - "@backstage/core-plugin-api": ^1.10.0 - "@backstage/plugin-permission-common": ^0.8.1 - "@backstage/plugin-permission-react": ^0.4.27 - "@backstage/theme": ^0.6.0 - "@backstage/types": ^1.1.1 + "@backstage/config": ^1.3.0 + "@backstage/core-app-api": ^1.15.2 + "@backstage/core-plugin-api": ^1.10.1 + "@backstage/plugin-permission-common": ^0.8.2 + "@backstage/plugin-permission-react": ^0.4.28 + "@backstage/theme": ^0.6.2 + "@backstage/types": ^1.2.0 "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.9.1 cross-fetch: ^4.0.0 @@ -8674,7 +8908,7 @@ __metadata: optional: true "@types/react": optional: true - checksum: a2510b9b2cde88ba636af2d09d30d8349b80167a9408e416b2245771f5138dfd56745a6b08ecad64ec7f9656d2b5a15d9ab15dbcd695d3981db49e272d8a3260 + checksum: 2ef863129664a9c14f1e57c6c36bba873f7c2fcccf2a5dd5594f3773ba52aaed0695a7ae844bbf7f70483a3290421b48d78cb1d4634ac326006dfa30e1c9b306 languageName: node linkType: hard @@ -8733,9 +8967,9 @@ __metadata: languageName: node linkType: hard -"@backstage/theme@npm:^0.6.0": - version: 0.6.0 - resolution: "@backstage/theme@npm:0.6.0" +"@backstage/theme@npm:^0.6.0, @backstage/theme@npm:^0.6.2": + version: 0.6.2 + resolution: "@backstage/theme@npm:0.6.2" dependencies: "@emotion/react": ^11.10.5 "@emotion/styled": ^11.10.5 @@ -8749,7 +8983,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: d1cdaa069bc6eac3a38f947504ddc45a7d1d49ef429fdb9ff99b606cb07a686b5b86c98bed76e0b2404d1b401fd7e6f12ab7a272ebb483a61ea3d07b8d467b6f + checksum: 480bf041bea2919b1d0590c7ee45950d6f2eb00403e40e7a86a0b16c1994693d7c3d67e401ff771d2e920a849d8cb02207a0b1212f436aed973439f66e824803 languageName: node linkType: hard @@ -8780,7 +9014,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/types@^1.1.1, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": +"@backstage/types@^1.1.1, @backstage/types@^1.2.0, @backstage/types@workspace:^, @backstage/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@backstage/types@workspace:packages/types" dependencies: @@ -8820,6 +9054,30 @@ __metadata: languageName: node linkType: hard +"@base_ui/react@npm:^1.0.0-alpha.3": + version: 1.0.0-alpha.3 + resolution: "@base_ui/react@npm:1.0.0-alpha.3" + dependencies: + "@babel/runtime": ^7.25.6 + "@floating-ui/react": ^0.26.24 + "@floating-ui/react-dom": ^2.1.2 + "@floating-ui/utils": ^0.2.8 + "@mui/types": ^7.2.17 + "@mui/utils": ^6.1.1 + clsx: ^2.1.1 + prop-types: ^15.8.1 + use-sync-external-store: ^1.2.2 + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 + react-dom: ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: c725386d8a6cb351742751a115dc3f06d6bf910470912457bb184646dc3890e3a3a971a1364ca2219192524a9cfbb96adc57339c2d54b931342ce705ce5ac220 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -8862,13 +9120,13 @@ __metadata: languageName: node linkType: hard -"@changesets/apply-release-plan@npm:^7.0.5": - version: 7.0.5 - resolution: "@changesets/apply-release-plan@npm:7.0.5" +"@changesets/apply-release-plan@npm:^7.0.6": + version: 7.0.6 + resolution: "@changesets/apply-release-plan@npm:7.0.6" dependencies: - "@changesets/config": ^3.0.3 + "@changesets/config": ^3.0.4 "@changesets/get-version-range-type": ^0.4.0 - "@changesets/git": ^3.0.1 + "@changesets/git": ^3.0.2 "@changesets/should-skip-package": ^0.1.1 "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 @@ -8879,13 +9137,13 @@ __metadata: prettier: ^2.7.1 resolve-from: ^5.0.0 semver: ^7.5.3 - checksum: f6a1b90d89fd08b46c11fad05d5fee510ff8a1888c163fd6221ccfb045eab013fa57c0c32c5697d6406852a39cf4df01b44f3ecca4746f30bd610bec54aa9abf + checksum: d84049b0874fe86db35a18b3959eee5ccb0e1be095a4d4718495e47e1123580c219bbaf4522190394ce3c40380c03b4e83d00e15070f0df77887b15c69fab14c languageName: node linkType: hard -"@changesets/assemble-release-plan@npm:^6.0.4": - version: 6.0.4 - resolution: "@changesets/assemble-release-plan@npm:6.0.4" +"@changesets/assemble-release-plan@npm:^6.0.5": + version: 6.0.5 + resolution: "@changesets/assemble-release-plan@npm:6.0.5" dependencies: "@changesets/errors": ^0.2.0 "@changesets/get-dependents-graph": ^2.1.2 @@ -8893,7 +9151,7 @@ __metadata: "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 semver: ^7.5.3 - checksum: 948066a8ca8e12390599f641a0439b6a4d6c1c2a9958f58596aa50cf68d7d594b28acc1eb6bd0ad17df2025f0614006e44728a2614fad2a3d54c669568bf6d65 + checksum: d13c28a8666509a1e20dd496d2ec640ab11f610fcd88f69bd6c6166ae285ce647862e6a6a786d537f8d5070720dbca883cc4d1b08f83ed08b8a89b26221ad6c2 languageName: node linkType: hard @@ -8907,20 +9165,20 @@ __metadata: linkType: hard "@changesets/cli@npm:^2.14.0": - version: 2.27.9 - resolution: "@changesets/cli@npm:2.27.9" + version: 2.27.10 + resolution: "@changesets/cli@npm:2.27.10" dependencies: - "@changesets/apply-release-plan": ^7.0.5 - "@changesets/assemble-release-plan": ^6.0.4 + "@changesets/apply-release-plan": ^7.0.6 + "@changesets/assemble-release-plan": ^6.0.5 "@changesets/changelog-git": ^0.2.0 - "@changesets/config": ^3.0.3 + "@changesets/config": ^3.0.4 "@changesets/errors": ^0.2.0 "@changesets/get-dependents-graph": ^2.1.2 - "@changesets/get-release-plan": ^4.0.4 - "@changesets/git": ^3.0.1 + "@changesets/get-release-plan": ^4.0.5 + "@changesets/git": ^3.0.2 "@changesets/logger": ^0.1.1 "@changesets/pre": ^2.0.1 - "@changesets/read": ^0.6.1 + "@changesets/read": ^0.6.2 "@changesets/should-skip-package": ^0.1.1 "@changesets/types": ^6.0.0 "@changesets/write": ^0.3.2 @@ -8936,17 +9194,17 @@ __metadata: picocolors: ^1.1.0 resolve-from: ^5.0.0 semver: ^7.5.3 - spawndamnit: ^2.0.0 + spawndamnit: ^3.0.1 term-size: ^2.1.0 bin: changeset: bin.js - checksum: 4bd36c152f9f93716b001f3ed849717588d2a9eb97f058e86f95ba6a43d8e4311073174251150aabb96f0a1ab5f8ab5ee6a32f85fc9248363f92b3826227cb9d + checksum: 9927bd57299d8b26c49ed48b2380cd19eb7b8a4fafd6babd5ec0d92d3b68cc7a54305201ce63142723de48bc5a9e75f611dd747d5a7c6ac80a934a3c4a83399b languageName: node linkType: hard -"@changesets/config@npm:^3.0.3": - version: 3.0.3 - resolution: "@changesets/config@npm:3.0.3" +"@changesets/config@npm:^3.0.4": + version: 3.0.4 + resolution: "@changesets/config@npm:3.0.4" dependencies: "@changesets/errors": ^0.2.0 "@changesets/get-dependents-graph": ^2.1.2 @@ -8954,8 +9212,8 @@ __metadata: "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 fs-extra: ^7.0.1 - micromatch: ^4.0.2 - checksum: f216f497e09c0fcdd4c397fc3998d1651a171b89981d2bed2a6c23c0f55ffa4e240cadbd13902bf91c218686165689a5183674a5b4682d80d3d5b8b9c569f5f1 + micromatch: ^4.0.8 + checksum: 43763d930e7fc4f24f9bb7b974708cc72f13d1a3dca10ace21d63135b7ff47dbfa3461cc9842171ae0564e37b17da2cc2e6e3f69a3f180a28efce2389eceb7de languageName: node linkType: hard @@ -8980,17 +9238,17 @@ __metadata: languageName: node linkType: hard -"@changesets/get-release-plan@npm:^4.0.4": - version: 4.0.4 - resolution: "@changesets/get-release-plan@npm:4.0.4" +"@changesets/get-release-plan@npm:^4.0.5": + version: 4.0.5 + resolution: "@changesets/get-release-plan@npm:4.0.5" dependencies: - "@changesets/assemble-release-plan": ^6.0.4 - "@changesets/config": ^3.0.3 + "@changesets/assemble-release-plan": ^6.0.5 + "@changesets/config": ^3.0.4 "@changesets/pre": ^2.0.1 - "@changesets/read": ^0.6.1 + "@changesets/read": ^0.6.2 "@changesets/types": ^6.0.0 "@manypkg/get-packages": ^1.1.3 - checksum: 7217347f5bfaa56f97d3964e28e23a109d60c42b7c879c0cab6934feb30bdbdebb6dd0e81b4ecb5ec414be442d566b6af90d9224f6a48a52b6c5269c337f54a6 + checksum: 3e06ea36b814e9a36aaac3ab46102c01802d2cd262e9ec2705a63c461f43af44be48bd55bb6d86e6753b51aaac81d7c6e2a13bc2e8a86d60fe6bce481dbd2e27 languageName: node linkType: hard @@ -9001,16 +9259,16 @@ __metadata: languageName: node linkType: hard -"@changesets/git@npm:^3.0.1": - version: 3.0.1 - resolution: "@changesets/git@npm:3.0.1" +"@changesets/git@npm:^3.0.2": + version: 3.0.2 + resolution: "@changesets/git@npm:3.0.2" dependencies: "@changesets/errors": ^0.2.0 "@manypkg/get-packages": ^1.1.3 is-subdir: ^1.1.1 - micromatch: ^4.0.2 - spawndamnit: ^2.0.0 - checksum: 46d780fecd3dbdafde7c96dde7fe35a8461bc6edbff1de92d490971a99f021d60c5b4606a1d4fb778567146810090ede6610cf89407c14bde88edaa246801539 + micromatch: ^4.0.8 + spawndamnit: ^3.0.1 + checksum: 56d15fd74881fccd7d46aa8e4d6b808e8d5a349103a5a54f2dd52d91a17056b271b04c28f7709fb162bab48ecaee2f51678fca01ed77be5a8392bf8efa6340c7 languageName: node linkType: hard @@ -9045,18 +9303,18 @@ __metadata: languageName: node linkType: hard -"@changesets/read@npm:^0.6.1": - version: 0.6.1 - resolution: "@changesets/read@npm:0.6.1" +"@changesets/read@npm:^0.6.2": + version: 0.6.2 + resolution: "@changesets/read@npm:0.6.2" dependencies: - "@changesets/git": ^3.0.1 + "@changesets/git": ^3.0.2 "@changesets/logger": ^0.1.1 "@changesets/parse": ^0.4.0 "@changesets/types": ^6.0.0 fs-extra: ^7.0.1 p-filter: ^2.1.0 picocolors: ^1.1.0 - checksum: d00a18a3d04af5c76e7b763096650ebe16589864ab04eaf9e99c88aa77542f64de547b585037fc204d2055f9dd47fae94c789e2f173d3507a4e29dbe6609dd5b + checksum: e47e9a6417c92d9d81f1fb51bf8ba03296daa812acd84a0b30e007f89918822bec6d06148db00ed2fd2eab1fb705b9fa54da931ee8841cd470b1d36e42784ea1 languageName: node linkType: hard @@ -9096,6 +9354,21 @@ __metadata: languageName: node linkType: hard +"@chromatic-com/storybook@npm:^3.2.2": + version: 3.2.2 + resolution: "@chromatic-com/storybook@npm:3.2.2" + dependencies: + chromatic: ^11.15.0 + filesize: ^10.0.12 + jsonfile: ^6.1.0 + react-confetti: ^6.1.0 + strip-ansi: ^7.1.0 + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 8f1d03b32e131d391d41913b346d3898e5f2661c54dbe057f05fb1bce2d9b94581942bc5f90efe599b819d1f05d92c50a9be1e0cba2962be797f9a9551b568da + languageName: node + linkType: hard + "@codemirror/autocomplete@npm:^6.0.0": version: 6.3.0 resolution: "@codemirror/autocomplete@npm:6.3.0" @@ -9126,8 +9399,8 @@ __metadata: linkType: hard "@codemirror/language@npm:^6.0.0": - version: 6.10.3 - resolution: "@codemirror/language@npm:6.10.3" + version: 6.10.6 + resolution: "@codemirror/language@npm:6.10.6" dependencies: "@codemirror/state": ^6.0.0 "@codemirror/view": ^6.23.0 @@ -9135,7 +9408,7 @@ __metadata: "@lezer/highlight": ^1.0.0 "@lezer/lr": ^1.0.0 style-mod: ^4.0.0 - checksum: 53fb72299500f63706f78c888d6b5fd81043ea11ea2fa4c72c13c6d4794bb6f4ec29450208c56b4f40e839984b3dc73505262803fa61416baf588da389a7c577 + checksum: 0bd5e4da0c714b4d2aad2e2ad19bb803d9992e5f0d56da3fb2534e63b03b8a562bd8b9ac4439509c687b589e3eaa5a33339eda13d91e54a5d5a99e032d1be981 languageName: node linkType: hard @@ -9170,10 +9443,12 @@ __metadata: languageName: node linkType: hard -"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0": - version: 6.4.0 - resolution: "@codemirror/state@npm:6.4.0" - checksum: c5236fe5786f1b85d17273a5c17fa8aeb063658c1404ab18caeb6e7591663ec96b65d453ab8162f75839c3801b04cd55ba4bc48f44cb61ebfeeee383f89553c7 +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.5.0": + version: 6.5.0 + resolution: "@codemirror/state@npm:6.5.0" + dependencies: + "@marijn/find-cluster-break": ^1.0.0 + checksum: f7fbed072cc67bf250f7d231668a00b988748cacaaa2ce3ea74ff13c7c392db76000e7d517933521cc6ad9dc3651c7b6d33accab3e3d4b9816cd3c5714661a84 languageName: node linkType: hard @@ -9190,13 +9465,13 @@ __metadata: linkType: hard "@codemirror/view@npm:^6.0.0, @codemirror/view@npm:^6.23.0": - version: 6.34.3 - resolution: "@codemirror/view@npm:6.34.3" + version: 6.35.3 + resolution: "@codemirror/view@npm:6.35.3" dependencies: - "@codemirror/state": ^6.4.0 + "@codemirror/state": ^6.5.0 style-mod: ^4.1.0 w3c-keyname: ^2.2.4 - checksum: 371c5fc6ef52a4cb0f82d6fd014ce52fa31ddbaa8f7041c019ae49a695668d98d102b67d81f7a76006f768d894d7f9504cc4b2c2a359e243b9bf5e1979a0c4a3 + checksum: 09c2685c9345b23ea69d28f323f29d6e73a269e9ffa29ffbf6443c139b2c97fd1a87eced1c59553a3416a08aed3246e30dd5eb70d516159ac352ae422ff4394d languageName: node linkType: hard @@ -9280,35 +9555,35 @@ __metadata: languageName: node linkType: hard -"@emotion/babel-plugin@npm:^11.12.0": - version: 11.12.0 - resolution: "@emotion/babel-plugin@npm:11.12.0" +"@emotion/babel-plugin@npm:^11.13.5": + version: 11.13.5 + resolution: "@emotion/babel-plugin@npm:11.13.5" dependencies: "@babel/helper-module-imports": ^7.16.7 "@babel/runtime": ^7.18.3 "@emotion/hash": ^0.9.2 "@emotion/memoize": ^0.9.0 - "@emotion/serialize": ^1.2.0 + "@emotion/serialize": ^1.3.3 babel-plugin-macros: ^3.1.0 convert-source-map: ^1.5.0 escape-string-regexp: ^4.0.0 find-root: ^1.1.0 source-map: ^0.5.7 stylis: 4.2.0 - checksum: b5d4b3dfe97e6763794a42b5c3a027a560caa1aa6dcaf05c18e5969691368dd08245c077bad7397dcc720b53d29caeaaec1888121e68cfd9ab02ff52f6fef662 + checksum: c41df7e6c19520e76d1939f884be878bf88b5ba00bd3de9d05c5b6c5baa5051686ab124d7317a0645de1b017b574d8139ae1d6390ec267fbe8e85a5252afb542 languageName: node linkType: hard -"@emotion/cache@npm:^11.11.0, @emotion/cache@npm:^11.13.0": - version: 11.13.1 - resolution: "@emotion/cache@npm:11.13.1" +"@emotion/cache@npm:^11.11.0, @emotion/cache@npm:^11.13.5": + version: 11.13.5 + resolution: "@emotion/cache@npm:11.13.5" dependencies: "@emotion/memoize": ^0.9.0 "@emotion/sheet": ^1.4.0 - "@emotion/utils": ^1.4.0 + "@emotion/utils": ^1.4.2 "@emotion/weak-memoize": ^0.4.0 stylis: 4.2.0 - checksum: 94b161786a03a08a1e30257478fad9a9be1ac8585ddca0c6410d7411fd474fc8b0d6d1167d7d15bdb012d1fd8a1220ac2bbc79501ad9b292b83c17da0874d7de + checksum: d4429bcac07730dd65707b8203f855be3d1958183e05d265eeefbeab19822e70c87250fad9abaeaea575d844256d1b8fee348211ef905f7715234df0ee088188 languageName: node linkType: hard @@ -9319,7 +9594,7 @@ __metadata: languageName: node linkType: hard -"@emotion/hash@npm:^0.9.1, @emotion/hash@npm:^0.9.2": +"@emotion/hash@npm:^0.9.0, @emotion/hash@npm:^0.9.1, @emotion/hash@npm:^0.9.2": version: 0.9.2 resolution: "@emotion/hash@npm:0.9.2" checksum: 379bde2830ccb0328c2617ec009642321c0e009a46aa383dfbe75b679c6aea977ca698c832d225a893901f29d7b3eef0e38cf341f560f6b2b56f1ff23c172387 @@ -9359,15 +9634,15 @@ __metadata: linkType: hard "@emotion/react@npm:^11.10.5": - version: 11.13.3 - resolution: "@emotion/react@npm:11.13.3" + version: 11.13.5 + resolution: "@emotion/react@npm:11.13.5" dependencies: "@babel/runtime": ^7.18.3 - "@emotion/babel-plugin": ^11.12.0 - "@emotion/cache": ^11.13.0 - "@emotion/serialize": ^1.3.1 + "@emotion/babel-plugin": ^11.13.5 + "@emotion/cache": ^11.13.5 + "@emotion/serialize": ^1.3.3 "@emotion/use-insertion-effect-with-fallbacks": ^1.1.0 - "@emotion/utils": ^1.4.0 + "@emotion/utils": ^1.4.2 "@emotion/weak-memoize": ^0.4.0 hoist-non-react-statics: ^3.3.1 peerDependencies: @@ -9375,20 +9650,20 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: 0b58374bf28de914b49881f0060acfb908989869ebab63a2287773fc5e91a39f15552632b03d376c3e9835c5b4f23a5ebac8b0963b29af164d46c0a77ac928f0 + checksum: 25c6572bdb1472d622a41817881628eb311deafe507bbb1be95c6a4c2c23a19bdd011c368d5794c5a17a1fdf2b5db327480a4c0b85d9322078d531289c163225 languageName: node linkType: hard -"@emotion/serialize@npm:^1.2.0, @emotion/serialize@npm:^1.3.0, @emotion/serialize@npm:^1.3.1": - version: 1.3.1 - resolution: "@emotion/serialize@npm:1.3.1" +"@emotion/serialize@npm:^1.3.3": + version: 1.3.3 + resolution: "@emotion/serialize@npm:1.3.3" dependencies: "@emotion/hash": ^0.9.2 "@emotion/memoize": ^0.9.0 "@emotion/unitless": ^0.10.0 - "@emotion/utils": ^1.4.0 + "@emotion/utils": ^1.4.2 csstype: ^3.0.2 - checksum: 9a488b1ef8b1609a0a80a957c2e9387703c148bb6444e0b097957cfca5c501191e870d11bae32d73ffeb5fd653961b8dbbd1c2c7e371b062029c0ed31d34162e + checksum: 510331233767ae4e09e925287ca2c7269b320fa1d737ea86db5b3c861a734483ea832394c0c1fe5b21468fe335624a75e72818831d303ba38125f54f44ba02e7 languageName: node linkType: hard @@ -9400,22 +9675,22 @@ __metadata: linkType: hard "@emotion/styled@npm:^11.10.5": - version: 11.13.0 - resolution: "@emotion/styled@npm:11.13.0" + version: 11.13.5 + resolution: "@emotion/styled@npm:11.13.5" dependencies: "@babel/runtime": ^7.18.3 - "@emotion/babel-plugin": ^11.12.0 + "@emotion/babel-plugin": ^11.13.5 "@emotion/is-prop-valid": ^1.3.0 - "@emotion/serialize": ^1.3.0 + "@emotion/serialize": ^1.3.3 "@emotion/use-insertion-effect-with-fallbacks": ^1.1.0 - "@emotion/utils": ^1.4.0 + "@emotion/utils": ^1.4.2 peerDependencies: "@emotion/react": ^11.0.0-rc.0 react: ">=16.8.0" peerDependenciesMeta: "@types/react": optional: true - checksum: f5b951059418f57bc8ea32b238afb25965ece3314f2ffd1b14ce049ba3c066a424990dfbfabbf57bb88e044eaa80bf19f620ac988adda3d2fc483177be6da05e + checksum: 316b3e9f98fc9d3faa54a990ad7f3805611c76a4ebffac9a6c28b6e7e9dd6e9343e9b80c79617af7f64524081a606f3789a89373abf67362fa138028f91b62af languageName: node linkType: hard @@ -9449,10 +9724,10 @@ __metadata: languageName: node linkType: hard -"@emotion/utils@npm:^1.4.0": - version: 1.4.0 - resolution: "@emotion/utils@npm:1.4.0" - checksum: 212af0b0d6bcaa63c76e1a36e35bee4d3579359316c03bf970faabb5427a4c0aab3e2346a721bac54f0c8e027958e759c5682be78f308755a1d9753e83963621 +"@emotion/utils@npm:^1.4.2": + version: 1.4.2 + resolution: "@emotion/utils@npm:1.4.2" + checksum: 04cf76849c6401205c058b82689fd0ec5bf501aed6974880fe9681a1d61543efb97e848f4c38664ac4a9068c7ad2d1cb84f73bde6cf95f1208aa3c28e0190321 languageName: node linkType: hard @@ -9470,6 +9745,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/aix-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/aix-ppc64@npm:0.23.1" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/aix-ppc64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/aix-ppc64@npm:0.24.0" @@ -9484,6 +9766,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm64@npm:0.23.1" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/android-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/android-arm64@npm:0.24.0" @@ -9498,6 +9787,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm@npm:0.23.1" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/android-arm@npm:0.24.0" @@ -9512,6 +9808,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/android-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-x64@npm:0.23.1" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + "@esbuild/android-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/android-x64@npm:0.24.0" @@ -9526,6 +9829,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-arm64@npm:0.23.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/darwin-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/darwin-arm64@npm:0.24.0" @@ -9540,6 +9850,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/darwin-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-x64@npm:0.23.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + "@esbuild/darwin-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/darwin-x64@npm:0.24.0" @@ -9554,6 +9871,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-arm64@npm:0.23.1" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/freebsd-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/freebsd-arm64@npm:0.24.0" @@ -9568,6 +9892,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/freebsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-x64@npm:0.23.1" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/freebsd-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/freebsd-x64@npm:0.24.0" @@ -9582,6 +9913,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm64@npm:0.23.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/linux-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-arm64@npm:0.24.0" @@ -9596,6 +9934,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm@npm:0.23.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + "@esbuild/linux-arm@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-arm@npm:0.24.0" @@ -9610,6 +9955,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ia32@npm:0.23.1" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/linux-ia32@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-ia32@npm:0.24.0" @@ -9624,6 +9976,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-loong64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-loong64@npm:0.23.1" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + "@esbuild/linux-loong64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-loong64@npm:0.24.0" @@ -9638,6 +9997,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-mips64el@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-mips64el@npm:0.23.1" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + "@esbuild/linux-mips64el@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-mips64el@npm:0.24.0" @@ -9652,6 +10018,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ppc64@npm:0.23.1" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + "@esbuild/linux-ppc64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-ppc64@npm:0.24.0" @@ -9666,6 +10039,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-riscv64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-riscv64@npm:0.23.1" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + "@esbuild/linux-riscv64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-riscv64@npm:0.24.0" @@ -9680,6 +10060,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-s390x@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-s390x@npm:0.23.1" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + "@esbuild/linux-s390x@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-s390x@npm:0.24.0" @@ -9694,6 +10081,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/linux-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-x64@npm:0.23.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + "@esbuild/linux-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/linux-x64@npm:0.24.0" @@ -9708,6 +10102,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/netbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/netbsd-x64@npm:0.23.1" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/netbsd-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/netbsd-x64@npm:0.24.0" @@ -9715,6 +10116,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-arm64@npm:0.23.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/openbsd-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/openbsd-arm64@npm:0.24.0" @@ -9729,6 +10137,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/openbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-x64@npm:0.23.1" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + "@esbuild/openbsd-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/openbsd-x64@npm:0.24.0" @@ -9743,6 +10158,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/sunos-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/sunos-x64@npm:0.23.1" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + "@esbuild/sunos-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/sunos-x64@npm:0.24.0" @@ -9757,6 +10179,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-arm64@npm:0.23.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + "@esbuild/win32-arm64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/win32-arm64@npm:0.24.0" @@ -9771,6 +10200,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-ia32@npm:0.23.1" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + "@esbuild/win32-ia32@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/win32-ia32@npm:0.24.0" @@ -9785,6 +10221,13 @@ __metadata: languageName: node linkType: hard +"@esbuild/win32-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-x64@npm:0.23.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + "@esbuild/win32-x64@npm:0.24.0": version: 0.24.0 resolution: "@esbuild/win32-x64@npm:0.24.0" @@ -9848,41 +10291,55 @@ __metadata: languageName: node linkType: hard -"@floating-ui/core@npm:^1.0.0": - version: 1.6.0 - resolution: "@floating-ui/core@npm:1.6.0" +"@floating-ui/core@npm:^1.6.0": + version: 1.6.8 + resolution: "@floating-ui/core@npm:1.6.8" dependencies: - "@floating-ui/utils": ^0.2.1 - checksum: 2e25c53b0c124c5c9577972f8ae21d081f2f7895e6695836a53074463e8c65b47722744d6d2b5a993164936da006a268bcfe87fe68fd24dc235b1cb86bed3127 + "@floating-ui/utils": ^0.2.8 + checksum: 82faa6ea9d57e466779324e51308d6d49c098fb9d184a08d9bb7f4fad83f08cc070fc491f8d56f0cad44a16215fb43f9f829524288413e6c33afcb17303698de languageName: node linkType: hard -"@floating-ui/dom@npm:^1.6.1": - version: 1.6.3 - resolution: "@floating-ui/dom@npm:1.6.3" +"@floating-ui/dom@npm:^1.0.0": + version: 1.6.12 + resolution: "@floating-ui/dom@npm:1.6.12" dependencies: - "@floating-ui/core": ^1.0.0 - "@floating-ui/utils": ^0.2.0 - checksum: 81cbb18ece3afc37992f436e469e7fabab2e433248e46fff4302d12493a175b0c64310f8a971e6e1eda7218df28ace6b70237b0f3c22fe12a21bba05b5579555 + "@floating-ui/core": ^1.6.0 + "@floating-ui/utils": ^0.2.8 + checksum: 956514ed100c0c853e73ace9e3c877b7e535444d7c31326f687a7690d49cb1e59ef457e9c93b76141aea0d280e83ed5a983bb852718b62eea581f755454660f6 languageName: node linkType: hard -"@floating-ui/react-dom@npm:^2.0.0": - version: 2.0.8 - resolution: "@floating-ui/react-dom@npm:2.0.8" +"@floating-ui/react-dom@npm:^2.0.0, @floating-ui/react-dom@npm:^2.1.2": + version: 2.1.2 + resolution: "@floating-ui/react-dom@npm:2.1.2" dependencies: - "@floating-ui/dom": ^1.6.1 + "@floating-ui/dom": ^1.0.0 peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: 5da7f13a69281e38859a3203a608fe9de1d850b332b355c10c0c2427c7b7209a0374c10f6295b6577c1a70237af8b678340bd4cc0a4b1c66436a94755d81e526 + checksum: 25bb031686e23062ed4222a8946e76b3f9021d40a48437bd747233c4964a766204b8a55f34fa8b259839af96e60db7c6e3714d81f1de06914294f90e86ffbc48 languageName: node linkType: hard -"@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.1": - version: 0.2.1 - resolution: "@floating-ui/utils@npm:0.2.1" - checksum: 9ed4380653c7c217cd6f66ae51f20fdce433730dbc77f95b5abfb5a808f5fdb029c6ae249b4e0490a816f2453aa6e586d9a873cd157fdba4690f65628efc6e06 +"@floating-ui/react@npm:^0.26.24": + version: 0.26.28 + resolution: "@floating-ui/react@npm:0.26.28" + dependencies: + "@floating-ui/react-dom": ^2.1.2 + "@floating-ui/utils": ^0.2.8 + tabbable: ^6.0.0 + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 1bfcccdb1f388ceb0075dc3e46934f4f04ef10bff2f971e1bf79067391c8729b366025caca0a42f5ca80854820a621a9edecbacdc046c33eb428f508fd6ce1f3 + languageName: node + linkType: hard + +"@floating-ui/utils@npm:^0.2.8": + version: 0.2.8 + resolution: "@floating-ui/utils@npm:0.2.8" + checksum: deb98bba017c4e073c7ad5740d4dec33a4d3e0942d412e677ac0504f3dade15a68fc6fd164d43c93c0bb0bcc5dc5015c1f4080dfb1a6161140fe660624f7c875 languageName: node linkType: hard @@ -9893,7 +10350,7 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/core@npm:^35.8.0, @gitbeaker/core@npm:^35.8.1": +"@gitbeaker/core@npm:^35.8.1": version: 35.8.1 resolution: "@gitbeaker/core@npm:35.8.1" dependencies: @@ -9907,17 +10364,6 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/core@npm:^39.34.3": - version: 39.34.3 - resolution: "@gitbeaker/core@npm:39.34.3" - dependencies: - "@gitbeaker/requester-utils": ^39.34.3 - qs: ^6.11.2 - xcase: ^2.0.1 - checksum: 2b0ccd6137ee717b6f51c51c8f7063b84beeebfdb044574f2257f282864411c4f0932f2619893385f2a86bb4fa342b75be972fd1868640ab4e260f2280cc52b3 - languageName: node - linkType: hard - "@gitbeaker/core@npm:^40.6.0": version: 40.6.0 resolution: "@gitbeaker/core@npm:40.6.0" @@ -9929,7 +10375,18 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/node@npm:^35.1.0, @gitbeaker/node@npm:^35.8.0": +"@gitbeaker/core@npm:^41.3.0": + version: 41.3.0 + resolution: "@gitbeaker/core@npm:41.3.0" + dependencies: + "@gitbeaker/requester-utils": ^41.3.0 + qs: ^6.12.2 + xcase: ^2.0.1 + checksum: 7b42c2af717002a54a1a6fdaa4056f2dbf6b52c6c33de68d1ad035b301609322f5b980d0da48918518dde105f4d88b39976cf4510a3d19a34e11b991c111e8fc + languageName: node + linkType: hard + +"@gitbeaker/node@npm:^35.1.0": version: 35.8.1 resolution: "@gitbeaker/node@npm:35.8.1" dependencies: @@ -9953,18 +10410,6 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/requester-utils@npm:^39.34.3": - version: 39.34.3 - resolution: "@gitbeaker/requester-utils@npm:39.34.3" - dependencies: - picomatch-browser: ^2.2.6 - qs: ^6.11.2 - rate-limiter-flexible: ^4.0.0 - xcase: ^2.0.1 - checksum: 55881864f42e243d9cd73840ea44c9eee13be7974fa13fde241f19bc47915712532d5f7339a598cdd258c32193a37375719984d2630620ab8d962d6d7724cbeb - languageName: node - linkType: hard - "@gitbeaker/requester-utils@npm:^40.6.0": version: 40.6.0 resolution: "@gitbeaker/requester-utils@npm:40.6.0" @@ -9977,13 +10422,15 @@ __metadata: languageName: node linkType: hard -"@gitbeaker/rest@npm:^39.25.0": - version: 39.34.3 - resolution: "@gitbeaker/rest@npm:39.34.3" +"@gitbeaker/requester-utils@npm:^41.3.0": + version: 41.3.0 + resolution: "@gitbeaker/requester-utils@npm:41.3.0" dependencies: - "@gitbeaker/core": ^39.34.3 - "@gitbeaker/requester-utils": ^39.34.3 - checksum: e2a484891b12c71d4218168ab3884af14d036fb16a710ea023556a3d57dd220b13feaebd1f4aa3f61d0180c9f17b66f283650cd543416bb402d3bed8b6eaa465 + picomatch-browser: ^2.2.6 + qs: ^6.12.2 + rate-limiter-flexible: ^4.0.1 + xcase: ^2.0.1 + checksum: 28dc17e995450988e62f9e76557bf0a2fe0a41db2ffc3e088ed5c71009daaa1f26563ad67b61738c6ca5bfde9d25f067a189f4bc0a7e097d5ffa49991d24cd38 languageName: node linkType: hard @@ -9997,6 +10444,28 @@ __metadata: languageName: node linkType: hard +"@gitbeaker/rest@npm:^41.2.0": + version: 41.3.0 + resolution: "@gitbeaker/rest@npm:41.3.0" + dependencies: + "@gitbeaker/core": ^41.3.0 + "@gitbeaker/requester-utils": ^41.3.0 + checksum: 96aa8d5e7ff3ca0e27f874df8b435fb12d20e6975d2291de26c90b7c2e201c286ffd241884b609b2200ddc4e28a331563b1b2d6767a1dd0160fc341f88761016 + languageName: node + linkType: hard + +"@google-cloud/cloud-sql-connector@npm:^1.4.0": + version: 1.4.0 + resolution: "@google-cloud/cloud-sql-connector@npm:1.4.0" + dependencies: + "@googleapis/sqladmin": ^24.0.0 + gaxios: ^6.1.1 + google-auth-library: ^9.2.0 + p-throttle: ^5.1.0 + checksum: c4ac2cc8cc24cc5966f146fe5686493fdb0bb4fc43a27ec086bd116f5ce475ca88f5e5e5fb79d17e6c31fb1a752d2f7e94433db17eea787696556c45415a31a1 + languageName: node + linkType: hard + "@google-cloud/container@npm:^5.0.0": version: 5.19.0 resolution: "@google-cloud/container@npm:5.19.0" @@ -10007,15 +10476,15 @@ __metadata: linkType: hard "@google-cloud/firestore@npm:^7.0.0": - version: 7.10.0 - resolution: "@google-cloud/firestore@npm:7.10.0" + version: 7.11.0 + resolution: "@google-cloud/firestore@npm:7.11.0" dependencies: "@opentelemetry/api": ^1.3.0 fast-deep-equal: ^3.1.1 functional-red-black-tree: ^1.0.1 google-gax: ^4.3.3 protobufjs: ^7.2.6 - checksum: c534e49c6b52b7b46366eba009e3f56e8ee10ca0501896a7794470cab32513c6a314f364ff5a3fe5a44b832ba39d1afc86d38b42be3826a615c0a59108185c7d + checksum: b926123db5e3f37704c0aa51baee1726b72910a37c7fe99bbfe048afb1fba7fa40d7e5f7c017c7284ebd9273c0237da5c00fac81772ba0de1bed97dc9b71e709 languageName: node linkType: hard @@ -10066,6 +10535,15 @@ __metadata: languageName: node linkType: hard +"@googleapis/sqladmin@npm:^24.0.0": + version: 24.0.0 + resolution: "@googleapis/sqladmin@npm:24.0.0" + dependencies: + googleapis-common: ^7.0.0 + checksum: b1c93d18b800ecd5af79dc6728e6b030f6918a1c5e2094d2dd7b460e3b2033cb9ce4f4ffe5b6155ecc2f699b8e4bdf0a94999786671b8fa05e1d8f3ce90cf466 + languageName: node + linkType: hard + "@graphiql/react@npm:^0.20.3": version: 0.20.3 resolution: "@graphiql/react@npm:0.20.3" @@ -10678,6 +11156,7 @@ __metadata: resolution: "@internal/scaffolder@workspace:packages/scaffolder-internal" dependencies: "@backstage/cli": "workspace:^" + "@backstage/frontend-plugin-api": "workspace:^" "@backstage/plugin-scaffolder-react": "workspace:^" zod: ^3.22.4 languageName: unknown @@ -11022,10 +11501,10 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": - version: 1.4.15 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15, @jridgewell/sourcemap-codec@npm:^1.5.0": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 05df4f2538b3b0f998ea4c1cd34574d0feba216fa5d4ccaef0187d12abf82eafe6021cec8b49f9bb4d90f2ba4582ccc581e72986a5fcf4176ae0cfeb04cf52ec languageName: node linkType: hard @@ -11063,21 +11542,21 @@ __metadata: languageName: node linkType: hard -"@jsep-plugin/assignment@npm:^1.2.1": - version: 1.2.1 - resolution: "@jsep-plugin/assignment@npm:1.2.1" +"@jsep-plugin/assignment@npm:^1.3.0": + version: 1.3.0 + resolution: "@jsep-plugin/assignment@npm:1.3.0" peerDependencies: jsep: ^0.4.0||^1.0.0 - checksum: d56fd7423c59dd269c50b0a9c22ec05f099a789ec8e8980f2307782f496ab3f0740151f1bdc7a1f3a8ee9085cdeb6f5b4def0d6b312e6b93ab160e6489b400f2 + checksum: 5549497d403a6c00969d61202a6d3dafc5a349929d190a524363dcfacb3436dbda3d9f88b2ec1330247a594ad3c5f1c17b0997769d0b206802281bad6cf9a410 languageName: node linkType: hard -"@jsep-plugin/regex@npm:^1.0.1, @jsep-plugin/regex@npm:^1.0.3": - version: 1.0.3 - resolution: "@jsep-plugin/regex@npm:1.0.3" +"@jsep-plugin/regex@npm:^1.0.1, @jsep-plugin/regex@npm:^1.0.4": + version: 1.0.4 + resolution: "@jsep-plugin/regex@npm:1.0.4" peerDependencies: jsep: ^0.4.0||^1.0.0 - checksum: a57718ae5c86bd10ff5de51843a771b96a10a9c6b5c5f4e02aa5318257c3d5fdec96f8b389fcbe129c7a6ad6b0746d9a0fd934c949b80882230fbc14b548c922 + checksum: 78ef01554535ac6c108851a2a6d86377bce10de01a263ad7b31f9b37c8aa9fc6c49f24b753e5da7d771c5921c913e43c1c33e0bc0fa5d02562d906c83a237836 languageName: node linkType: hard @@ -11107,6 +11586,17 @@ __metadata: languageName: node linkType: hard +"@keyv/memcache@npm:^2.0.1": + version: 2.0.1 + resolution: "@keyv/memcache@npm:2.0.1" + dependencies: + "@keyv/serialize": "*" + buffer: ^6.0.3 + memjs: ^1.3.2 + checksum: 357b320fb3998e7bff9e3a5702da3cc0d4337586f1a04392dfb490cef7af2c039c3ecda922b18029cc9de6e9310a91cde1602b0851fb86acb93b629200458cc2 + languageName: node + linkType: hard + "@keyv/redis@npm:^2.5.3": version: 2.8.5 resolution: "@keyv/redis@npm:2.8.5" @@ -11116,25 +11606,44 @@ __metadata: languageName: node linkType: hard -"@kubernetes-models/apimachinery@npm:^2.0.0": - version: 2.0.0 - resolution: "@kubernetes-models/apimachinery@npm:2.0.0" +"@keyv/redis@npm:^4.0.1": + version: 4.0.2 + resolution: "@keyv/redis@npm:4.0.2" dependencies: - "@kubernetes-models/base": ^5.0.0 - "@kubernetes-models/validate": ^4.0.0 - "@swc/helpers": ^0.5.8 - checksum: 0e9ed8f05166221e2ccfe21a45a3aa480ab31c8e8b97b2dbb22d1d3c60477fb0b093def5d78727ba1037df4f14a9c7f38a7da0432c769fdc606097b4b6018dd6 + keyv: "*" + redis: ^4.7.0 + checksum: 356dcf125072b35be45649fcf5af5e5400b0227b25013d2f7494176a920654a1de63cb95e2a4a661b7db4c1cef8b7553d6e33603ace03d5fbe0a7e22955c9f2b languageName: node linkType: hard -"@kubernetes-models/base@npm:^5.0.0": - version: 5.0.0 - resolution: "@kubernetes-models/base@npm:5.0.0" +"@keyv/serialize@npm:*": + version: 1.0.1 + resolution: "@keyv/serialize@npm:1.0.1" + dependencies: + buffer: ^6.0.3 + checksum: ff3dd9a6246b17fca3d1b0aba312dea931059fdecc36027f4d8133e59dbb3554a0a516b1f3dfc7fb2b3ca7a3d6fa307804f299566ab214febd3fb9d0502eebed + languageName: node + linkType: hard + +"@kubernetes-models/apimachinery@npm:^2.0.0, @kubernetes-models/apimachinery@npm:^2.0.2": + version: 2.0.2 + resolution: "@kubernetes-models/apimachinery@npm:2.0.2" + dependencies: + "@kubernetes-models/base": ^5.0.1 + "@kubernetes-models/validate": ^4.0.0 + "@swc/helpers": ^0.5.8 + checksum: f99c50fc3c8446e6b525b74970c7dafe217fe3ffb944078c70b6c21ca0138040b44d094b57fb9218b1e52a5e4c802f1ea93d57c776b08eee59874be286f5545d + languageName: node + linkType: hard + +"@kubernetes-models/base@npm:^5.0.0, @kubernetes-models/base@npm:^5.0.1": + version: 5.0.1 + resolution: "@kubernetes-models/base@npm:5.0.1" dependencies: "@kubernetes-models/validate": ^4.0.0 is-plain-object: ^5.0.0 tslib: ^2.4.0 - checksum: 3ac064e6c18d88f356b8e91d320e08ee31a12a3ecd47d6d86e23566203125640b88223bc9003d02d420b6a9a86f2990f65e4a26c32ed075ef0753d8599549c0b + checksum: 9d0506b9b4b4ac366feb97f574e84f59d957377bb5c4c929332c3db8bd58bb70bcb1045d007d89369a73521591f7d0d5f651c43fca0779ed65d157258b6fd59a languageName: node linkType: hard @@ -11283,6 +11792,13 @@ __metadata: languageName: node linkType: hard +"@marijn/find-cluster-break@npm:^1.0.0": + version: 1.0.2 + resolution: "@marijn/find-cluster-break@npm:1.0.2" + checksum: 0d836de25e04d58325813401ef3c2d34caf040da985a5935fcbc9d84e7b47a21bdb15f57d70c2bf0960bd29ed3dbbb1afd00cdd0fc4fafbee7fd0ffe7d508ae1 + languageName: node + linkType: hard + "@material-table/core@npm:^3.1.0": version: 3.2.5 resolution: "@material-table/core@npm:3.2.5" @@ -11501,6 +12017,18 @@ __metadata: languageName: node linkType: hard +"@mdx-js/react@npm:^3.0.0": + version: 3.1.0 + resolution: "@mdx-js/react@npm:3.1.0" + dependencies: + "@types/mdx": ^2.0.0 + peerDependencies: + "@types/react": ">=16" + react: ">=16" + checksum: c5a9c495f43f498ece24a768762a1743abe2be33d050d7eab731beb754e631700547f039198c6262c998d9a443906bd78811c3fa38bc2fb37659848161dac331 + languageName: node + linkType: hard + "@microsoft/api-documenter@npm:^7.25.7": version: 7.25.14 resolution: "@microsoft/api-documenter@npm:7.25.14" @@ -11585,39 +12113,39 @@ __metadata: languageName: node linkType: hard -"@module-federation/bridge-react-webpack-plugin@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/bridge-react-webpack-plugin@npm:0.7.3" +"@module-federation/bridge-react-webpack-plugin@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/bridge-react-webpack-plugin@npm:0.8.1" dependencies: - "@module-federation/sdk": 0.7.3 + "@module-federation/sdk": 0.8.1 "@types/semver": 7.5.8 semver: 7.6.3 - checksum: 3d95dc760a1f1fff6d95da1410425a2fbfbf6ca6159aca1ad5c499b9cc50e7dca438070e79e91c7c6a482666cd8078153ab77046e29abf5336fa7c3f07dd4bb6 + checksum: d8c68cd1ddd387e9ef6fba688aec68ef0fe59ec5138f3fc897d033227c0ddd04c4307b52c352a42e85c4b9ad5bc759cd811280960166f752f217df7aeb27a55b languageName: node linkType: hard -"@module-federation/data-prefetch@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/data-prefetch@npm:0.7.3" +"@module-federation/data-prefetch@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/data-prefetch@npm:0.8.1" dependencies: - "@module-federation/runtime": 0.7.3 - "@module-federation/sdk": 0.7.3 + "@module-federation/runtime": 0.8.1 + "@module-federation/sdk": 0.8.1 fs-extra: 9.1.0 peerDependencies: react: ">=16.9.0" react-dom: ">=16.9.0" - checksum: e1952b298052a3703799e4808198763e27af6030a4bf57312c5bbbd08873e01e3b264a4d44e1261733f9f391c61dde56b6b6781220f0192ba3f85b084ff47d6a + checksum: 25a67256c1900d3989c2f393aca50a0f38faeb9aa1023327ce0716585fb4e19593efb147f20eac883d4eeae619400a95ec41e64f8b10a780b2e3a6e22495440c languageName: node linkType: hard -"@module-federation/dts-plugin@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/dts-plugin@npm:0.7.3" +"@module-federation/dts-plugin@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/dts-plugin@npm:0.8.1" dependencies: - "@module-federation/error-codes": 0.7.3 - "@module-federation/managers": 0.7.3 - "@module-federation/sdk": 0.7.3 - "@module-federation/third-party-dts-extractor": 0.7.3 + "@module-federation/error-codes": 0.8.1 + "@module-federation/managers": 0.8.1 + "@module-federation/sdk": 0.8.1 + "@module-federation/third-party-dts-extractor": 0.8.1 adm-zip: ^0.5.10 ansi-colors: ^4.1.3 axios: ^1.7.4 @@ -11636,22 +12164,22 @@ __metadata: peerDependenciesMeta: vue-tsc: optional: true - checksum: 20c74e809a5d1826ff0c3976e38da15d3f375e3b32d73845b0b8cd17958e1720701c4a23d0954676eb1e7444b4c6dc8c35dd5c9033b0091cd63ef944cfd8d122 + checksum: 7f3f6b000f2427b3ba06c14a3cf7332bec1a4f843d46d11fd267d041f0916ebe4458187284d640524187bae3c871714df29c817d136a45f0a59ae915cc8d77f2 languageName: node linkType: hard -"@module-federation/enhanced@npm:^0.7.0": - version: 0.7.3 - resolution: "@module-federation/enhanced@npm:0.7.3" +"@module-federation/enhanced@npm:^0.8.0": + version: 0.8.1 + resolution: "@module-federation/enhanced@npm:0.8.1" dependencies: - "@module-federation/bridge-react-webpack-plugin": 0.7.3 - "@module-federation/data-prefetch": 0.7.3 - "@module-federation/dts-plugin": 0.7.3 - "@module-federation/managers": 0.7.3 - "@module-federation/manifest": 0.7.3 - "@module-federation/rspack": 0.7.3 - "@module-federation/runtime-tools": 0.7.3 - "@module-federation/sdk": 0.7.3 + "@module-federation/bridge-react-webpack-plugin": 0.8.1 + "@module-federation/data-prefetch": 0.8.1 + "@module-federation/dts-plugin": 0.8.1 + "@module-federation/managers": 0.8.1 + "@module-federation/manifest": 0.8.1 + "@module-federation/rspack": 0.8.1 + "@module-federation/runtime-tools": 0.8.1 + "@module-federation/sdk": 0.8.1 btoa: ^1.2.1 upath: 2.0.1 peerDependencies: @@ -11665,52 +12193,53 @@ __metadata: optional: true webpack: optional: true - checksum: 5b3993a489cb724bccc6f13c6ee15dbe88438f2ab3bf1b1b69c22c825030b72e515227f75044d582ce3ae3aa65ad686fc19d13b75c5bcf03c9fbafbff000b375 + checksum: a4902eff5e6379c70638efd1cd80daa156dee8e3eded0bdf431535dd89abc1fbf14c0bd858905595ea9963639f2b72a404f4c8ddc2c8b45d7bc760fc3b2a361b languageName: node linkType: hard -"@module-federation/error-codes@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/error-codes@npm:0.7.3" - checksum: cbc207530f355c223e07f4aa79b0d78b5022f278395a0cb95190efcfe6708b3dbba3f40c96a7e663644e9fe28d2984daa79574387648e7c457e7f9268661edd0 +"@module-federation/error-codes@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/error-codes@npm:0.8.1" + checksum: 36d899d2d3e00904c8aa74f1611edfceb88937ee56cc5cf2302f30e010752c68c0486cf5251ee83c1f3c2471bcea1e1ea0e8047173e92e4f10bad83125b1721d languageName: node linkType: hard -"@module-federation/managers@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/managers@npm:0.7.3" +"@module-federation/managers@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/managers@npm:0.8.1" dependencies: - "@module-federation/sdk": 0.7.3 + "@module-federation/sdk": 0.8.1 find-pkg: 2.0.0 fs-extra: 9.1.0 - checksum: 162844cb587adfb70daed500381046e89bd5c9e678518763333e213faed0bef7763652d11a016719fc430f0b3c263ba4942a05fe11127218a8848ac156d21ed4 + checksum: 9f608960e5353934d85c99d68e41a156d79ca592ec52bb81ce869084cb7428d821165b17600ffd440b4640205d11fdd463165df35d6b9163250b64815c20e48b languageName: node linkType: hard -"@module-federation/manifest@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/manifest@npm:0.7.3" +"@module-federation/manifest@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/manifest@npm:0.8.1" dependencies: - "@module-federation/dts-plugin": 0.7.3 - "@module-federation/managers": 0.7.3 - "@module-federation/sdk": 0.7.3 + "@module-federation/dts-plugin": 0.8.1 + "@module-federation/managers": 0.8.1 + "@module-federation/sdk": 0.8.1 chalk: 3.0.0 find-pkg: 2.0.0 - checksum: 5211b8685f2566c0b373463dd9b3eae26c2c963f40b0d4f11dc6c7b0fdafc24c3aea406d3f612b2df16ec15291d1d26d30fb9ee028eee51b16568933f0d62b7a + checksum: 570eeb5fb36ecaac45ff150475cf09b69cf7fd2f7544527510732be65238957ef8f71faeebbeaf4d5fdfc2df2b3c88617982dcdbc93110a6766424306b8744cc languageName: node linkType: hard -"@module-federation/rspack@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/rspack@npm:0.7.3" +"@module-federation/rspack@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/rspack@npm:0.8.1" dependencies: - "@module-federation/bridge-react-webpack-plugin": 0.7.3 - "@module-federation/dts-plugin": 0.7.3 - "@module-federation/managers": 0.7.3 - "@module-federation/manifest": 0.7.3 - "@module-federation/runtime-tools": 0.7.3 - "@module-federation/sdk": 0.7.3 + "@module-federation/bridge-react-webpack-plugin": 0.8.1 + "@module-federation/dts-plugin": 0.8.1 + "@module-federation/managers": 0.8.1 + "@module-federation/manifest": 0.8.1 + "@module-federation/runtime-tools": 0.8.1 + "@module-federation/sdk": 0.8.1 peerDependencies: + "@rspack/core": ">=0.7" typescript: ^4.9.0 || ^5.0.0 vue-tsc: ">=1.0.24" peerDependenciesMeta: @@ -11718,7 +12247,7 @@ __metadata: optional: true vue-tsc: optional: true - checksum: 03dce49f24a24beb78282131296806a87c1c0ffed3ef47612493bd29ea81ffb17d67e63c88a8ce9da4be1b080bb5b831efe0fddc4bcb4e94b583d4b9f1dc6128 + checksum: a03ef54111d16fcf388acac7e1a8b4c6f2cb0af7a907d6e8d14aca2e321864997fa343902170f455e456aea978e6330a9050f070ff0a3503047c0bbed4ef08bb languageName: node linkType: hard @@ -11732,13 +12261,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime-tools@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/runtime-tools@npm:0.7.3" +"@module-federation/runtime-tools@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/runtime-tools@npm:0.8.1" dependencies: - "@module-federation/runtime": 0.7.3 - "@module-federation/webpack-bundler-runtime": 0.7.3 - checksum: a8519a15a05427df80eac038f5d46921044e7ea95b27c7a4c41cede0303b306ea4b071247f016116cf0681189a4352783e866f239fef8ac0e77698e430f1f71e + "@module-federation/runtime": 0.8.1 + "@module-federation/webpack-bundler-runtime": 0.8.1 + checksum: b10eca911e0a8611a7337f653c0efbd308805b561c22b27a3695092f674a95b349bbf7048659f53bddc558de82b3ffd3bda1757934edfcc298c60a779bfea319 languageName: node linkType: hard @@ -11751,13 +12280,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/runtime@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/runtime@npm:0.7.3" +"@module-federation/runtime@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/runtime@npm:0.8.1" dependencies: - "@module-federation/error-codes": 0.7.3 - "@module-federation/sdk": 0.7.3 - checksum: ce9439f4762828771dc49240a96527c4650e6f2421d76a995af75b20f3fc29d8e8af430e4b60620ab3093bda8785fb7c436a1fcdf4257f97159760431b8ce702 + "@module-federation/error-codes": 0.8.1 + "@module-federation/sdk": 0.8.1 + checksum: 31b4b23237ea105f85d316036819df1cab8d79e845e70b7a0365640f5cfb02850876c3b9fe1eb680aea8ae56454e58e6dfaa49a58c473d82c929307d6000c1f6 languageName: node linkType: hard @@ -11768,23 +12297,23 @@ __metadata: languageName: node linkType: hard -"@module-federation/sdk@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/sdk@npm:0.7.3" +"@module-federation/sdk@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/sdk@npm:0.8.1" dependencies: isomorphic-rslog: 0.0.6 - checksum: cb58b1537a1bd19d8e7d3d64685545fbc0be862a9e11878b3c1c55ba0b4e94b55f913f78ac87b8a713abbb4589279da20696cc8b740b87e9f5eac32276cf7fcd + checksum: 41858b512cba814ea4a483a03043c3fda7c50796be5ef9b360b73fc1a2903f1edc58194663efbbcb36cb8035d088db8fe94369f08735761c88fa342bf4d569d8 languageName: node linkType: hard -"@module-federation/third-party-dts-extractor@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/third-party-dts-extractor@npm:0.7.3" +"@module-federation/third-party-dts-extractor@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/third-party-dts-extractor@npm:0.8.1" dependencies: find-pkg: 2.0.0 fs-extra: 9.1.0 resolve: 1.22.8 - checksum: 72f23de2780eff7ea7d96b14d7fbdae9ed6c71f1ffcbc625d5e8d804225ca51d297a345d1be9793339da7c3a6c3fece05e542b9d34be08940bb273b27cd22f4a + checksum: fcf0eb87296f8a393db77adb74423af174bc5f0018201471af129d831e4c1c6cf9ab9ea4ae66b91785964a4b421fcfc2dc2079aeb687ad2c6ce891022c8d3adf languageName: node linkType: hard @@ -11798,13 +12327,13 @@ __metadata: languageName: node linkType: hard -"@module-federation/webpack-bundler-runtime@npm:0.7.3": - version: 0.7.3 - resolution: "@module-federation/webpack-bundler-runtime@npm:0.7.3" +"@module-federation/webpack-bundler-runtime@npm:0.8.1": + version: 0.8.1 + resolution: "@module-federation/webpack-bundler-runtime@npm:0.8.1" dependencies: - "@module-federation/runtime": 0.7.3 - "@module-federation/sdk": 0.7.3 - checksum: c177c1291727de315cc5cedbb55c5926a58b0bc025195a224fc98aa6dffbabd27645f99ccfa4c4bbc942a27f3f535c1e8d0f41f3c3cc80376af023249e1bd746 + "@module-federation/runtime": 0.8.1 + "@module-federation/sdk": 0.8.1 + checksum: 512ce759214bb82abaf51a2bcdb1eb6db524a819890822689f3be31d189b169827894195f6a5ad53e5afaacb1f08772123f37bce0b7b1dcc72545344e2c4fa31 languageName: node linkType: hard @@ -11912,9 +12441,9 @@ __metadata: languageName: node linkType: hard -"@mswjs/interceptors@npm:^0.36.5": - version: 0.36.9 - resolution: "@mswjs/interceptors@npm:0.36.9" +"@mswjs/interceptors@npm:^0.37.0": + version: 0.37.1 + resolution: "@mswjs/interceptors@npm:0.37.1" dependencies: "@open-draft/deferred-promise": ^2.2.0 "@open-draft/logger": ^0.3.0 @@ -11922,26 +12451,26 @@ __metadata: is-node-process: ^1.2.0 outvariant: ^1.4.3 strict-event-emitter: ^0.5.1 - checksum: 9d661ac98510e93356f546b0f2412e2d294baf650b3bd297995d7aa29ae4a939807368804ade7118edf8dca49f917bb901acfc1d6bbd4182817a9d30b3757d4f + checksum: 89f3717ff50595eb4075c540ce9c143290cdd24474ac7957097c4e6f53ad7536f1868cddce5b44d4344981fe837b31f127113cde1f15512929c8dba79767858d languageName: node linkType: hard -"@mui/core-downloads-tracker@npm:^5.16.7": - version: 5.16.7 - resolution: "@mui/core-downloads-tracker@npm:5.16.7" - checksum: b65c48ba2bf6bba6435ba9f2d6c33db0c8a85b3ff7599136a9682b72205bec76470ab5ed5e6e625d5bd012ed9bcbc641ed677548be80d217c9fb5d0435567062 +"@mui/core-downloads-tracker@npm:^5.16.9": + version: 5.16.9 + resolution: "@mui/core-downloads-tracker@npm:5.16.9" + checksum: 25e7cf746627e12671e2bae4ea8f81967fbb7e05188c268052104d05f249eea1baa3f3d97f66d1242112afa944a7b025a331527392797d620acbcc1dde23a3df languageName: node linkType: hard "@mui/material@npm:^5.12.2": - version: 5.16.7 - resolution: "@mui/material@npm:5.16.7" + version: 5.16.9 + resolution: "@mui/material@npm:5.16.9" dependencies: "@babel/runtime": ^7.23.9 - "@mui/core-downloads-tracker": ^5.16.7 - "@mui/system": ^5.16.7 + "@mui/core-downloads-tracker": ^5.16.9 + "@mui/system": ^5.16.8 "@mui/types": ^7.2.15 - "@mui/utils": ^5.16.6 + "@mui/utils": ^5.16.8 "@popperjs/core": ^2.11.8 "@types/react-transition-group": ^4.4.10 clsx: ^2.1.0 @@ -11952,9 +12481,9 @@ __metadata: peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 - react-dom: ^17.0.0 || ^18.0.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@emotion/react": optional: true @@ -11962,30 +12491,30 @@ __metadata: optional: true "@types/react": optional: true - checksum: 5057b48c3ce554247de9a8f675bda9bbda079bc83a696c500525f3ebbd63315a44f1c2a7c83c2025dbd02d2722892e397a0af10c1219d45f6534e41d91a43cc0 + checksum: e3692ba08add0a4b959d7e5f754cf5bf934d30798a9256d1eb5bbf37021f81cf6cc0b86a3cb065815af7f2112c6a359e463a6641618d07559f93516e1374669e languageName: node linkType: hard -"@mui/private-theming@npm:^5.16.6": - version: 5.16.6 - resolution: "@mui/private-theming@npm:5.16.6" +"@mui/private-theming@npm:^5.16.8": + version: 5.16.8 + resolution: "@mui/private-theming@npm:5.16.8" dependencies: "@babel/runtime": ^7.23.9 - "@mui/utils": ^5.16.6 + "@mui/utils": ^5.16.8 prop-types: ^15.8.1 peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 314ba598ab17cd425a36e4cab677ed26fe0939b23e53120da77cfbc3be6dada5428fa8e2a55cb697417599a4e3abfee6d4711de0a7318b9fb2c3a822b2d5b5a8 + checksum: 576cf19188c236482a8a698978d3061c7e8d76ba9d891d323ce96d92d6b80d88e1aa2a67fe4698d76b8a43221ef0f8ed21be74971fc684ce1279dc73fd34316b languageName: node linkType: hard -"@mui/styled-engine@npm:^5.16.6": - version: 5.16.6 - resolution: "@mui/styled-engine@npm:5.16.6" +"@mui/styled-engine@npm:^5.16.8": + version: 5.16.8 + resolution: "@mui/styled-engine@npm:5.16.8" dependencies: "@babel/runtime": ^7.23.9 "@emotion/cache": ^11.11.0 @@ -11994,25 +12523,25 @@ __metadata: peerDependencies: "@emotion/react": ^11.4.1 "@emotion/styled": ^11.3.0 - react: ^17.0.0 || ^18.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@emotion/react": optional: true "@emotion/styled": optional: true - checksum: 604f83b91801945336db211a8273061132668d01e9f456c30bb811a3b49cc5786b8b7dd8e0b5b89de15f6209abc900d9e679d3ae7a4651a6df45e323b6ed95c5 + checksum: 8eab246e985bbe2707af4620a3193166bacefb029df65ac846cfc0ac5d7996fcb72c50327241f60913538f58a2ad9aa6de3ef12b72eb7750c71f8d3c284a420b languageName: node linkType: hard "@mui/styles@npm:^5.14.18": - version: 5.16.7 - resolution: "@mui/styles@npm:5.16.7" + version: 5.16.10 + resolution: "@mui/styles@npm:5.16.10" dependencies: "@babel/runtime": ^7.23.9 "@emotion/hash": ^0.9.1 - "@mui/private-theming": ^5.16.6 + "@mui/private-theming": ^5.16.8 "@mui/types": ^7.2.15 - "@mui/utils": ^5.16.6 + "@mui/utils": ^5.16.8 clsx: ^2.1.0 csstype: ^3.1.3 hoist-non-react-statics: ^3.3.2 @@ -12026,32 +12555,32 @@ __metadata: jss-plugin-vendor-prefixer: ^10.10.0 prop-types: ^15.8.1 peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 1109eb150cf40782a6f24bebf6d22d55ea8c36bbf43893664c303e679b7d235a6578b2f2e1d9ee64132aa24496a15fd32f80278cb641208c3a372bd53679e1c0 + checksum: 7e85e030993f9e2d93f2f32c4c6f65febd882c8f8d324a1d9476845c8bf8e26fce588fb1336caeb7eea19453454eead92ee8493caa36fed5ce51089899c8ca1b languageName: node linkType: hard -"@mui/system@npm:^5.16.7": - version: 5.16.7 - resolution: "@mui/system@npm:5.16.7" +"@mui/system@npm:^5.16.8": + version: 5.16.8 + resolution: "@mui/system@npm:5.16.8" dependencies: "@babel/runtime": ^7.23.9 - "@mui/private-theming": ^5.16.6 - "@mui/styled-engine": ^5.16.6 + "@mui/private-theming": ^5.16.8 + "@mui/styled-engine": ^5.16.8 "@mui/types": ^7.2.15 - "@mui/utils": ^5.16.6 + "@mui/utils": ^5.16.8 clsx: ^2.1.0 csstype: ^3.1.3 prop-types: ^15.8.1 peerDependencies: "@emotion/react": ^11.5.0 "@emotion/styled": ^11.3.0 - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@emotion/react": optional: true @@ -12059,25 +12588,25 @@ __metadata: optional: true "@types/react": optional: true - checksum: 86cc11d062645b6742328178ca3a9e2aa2c6d064a559e4fb8c6c6bb8251794959b9dad385f9508fdcab2ae2764503c80f7c3d4f6eb1e0e8aa649f28d4f59133b + checksum: 8082b176009fa907cdb0391db59db6cd3589659ad92497caec998c01e1683978ab2eda4ece4d12e523d233b062aa5946d4a438d9a22bf172f0568be1db773e9c languageName: node linkType: hard -"@mui/types@npm:^7.2.15": - version: 7.2.16 - resolution: "@mui/types@npm:7.2.16" +"@mui/types@npm:^7.2.15, @mui/types@npm:^7.2.17, @mui/types@npm:^7.2.19": + version: 7.2.19 + resolution: "@mui/types@npm:7.2.19" peerDependencies: "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 7bb86487be8e55a4e138a6a5878ab272caee71546a7a2368223274afae65229f673334e59b8e3f7717ea7ea8d44af5f068b2eb4c212cddb98fefecfa873b868a + checksum: c3b5723e6f0861d47df834c57878f19347aefecdaf948cf9a25a64b73fbc75791430693d0f540b2bdc01bdfc605dc32bf4ba738113ec415aa9eaf002ce38f064 languageName: node linkType: hard -"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.16.6": - version: 5.16.6 - resolution: "@mui/utils@npm:5.16.6" +"@mui/utils@npm:^5.14.15, @mui/utils@npm:^5.16.8": + version: 5.16.8 + resolution: "@mui/utils@npm:5.16.8" dependencies: "@babel/runtime": ^7.23.9 "@mui/types": ^7.2.15 @@ -12086,12 +12615,32 @@ __metadata: prop-types: ^15.8.1 react-is: ^18.3.1 peerDependencies: - "@types/react": ^17.0.0 || ^18.0.0 - react: ^17.0.0 || ^18.0.0 + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 peerDependenciesMeta: "@types/react": optional: true - checksum: 6f8068f07f60a842fcb2e2540eecbd9c5f04df695bcc427184720e8ae138ae689fefd3c20147ab7c76e809ede6e10f5e08d1c34cd3a8b09bd22d2020a666a96f + checksum: ed714c6aa583bdf17af9f523c9b9ba3789a47677aa6408bc2afd842fa9eaa6d111361c1309435d481ea03b8c695e22ead98c43dc13239c63a3da481c95e5ad72 + languageName: node + linkType: hard + +"@mui/utils@npm:^6.1.1": + version: 6.1.9 + resolution: "@mui/utils@npm:6.1.9" + dependencies: + "@babel/runtime": ^7.26.0 + "@mui/types": ^7.2.19 + "@types/prop-types": ^15.7.13 + clsx: ^2.1.1 + prop-types: ^15.8.1 + react-is: ^18.3.1 + peerDependencies: + "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: a2c61c0537b312ab0faeb3f13e7f3b0736e11f29e7907ccd77b0643afc0dca3a0dceb3817371666f35ca8df723ddeac9b2bbb6b759206bde99e03514cfd4ebb9 languageName: node linkType: hard @@ -12236,6 +12785,19 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/agent@npm:3.0.0" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^10.0.1 + socks-proxy-agent: ^8.0.3 + checksum: e8fc25d536250ed3e669813b36e8c6d805628b472353c57afd8c4fde0fcfcf3dda4ffe22f7af8c9070812ec2e7a03fb41d7151547cef3508efe661a5a3add20f + languageName: node + linkType: hard + "@npmcli/arborist@npm:^4.0.4": version: 4.3.1 resolution: "@npmcli/arborist@npm:4.3.1" @@ -12307,6 +12869,15 @@ __metadata: languageName: node linkType: hard +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: ^7.3.5 + checksum: 68951c589e9a4328698a35fd82fe71909a257d6f2ede0434d236fa55634f0fbcad9bb8755553ce5849bd25ee6f019f4d435921ac715c853582c4a7f5983c8d4a + languageName: node + linkType: hard + "@npmcli/git@npm:^2.1.0": version: 2.1.0 resolution: "@npmcli/git@npm:2.1.0" @@ -13224,16 +13795,7 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api-logs@npm:0.54.1": - version: 0.54.1 - resolution: "@opentelemetry/api-logs@npm:0.54.1" - dependencies: - "@opentelemetry/api": ^1.3.0 - checksum: da3d2bd36f138ec1a56ea34b1601c6bf30be22f443b3a24f5df2cf293ed3f2601fb01ff00cb34a4ef08bd955b78f8259243dc757195f9ace7af4196896d32291 - languageName: node - linkType: hard - -"@opentelemetry/api-logs@npm:0.54.2, @opentelemetry/api-logs@npm:^0.54.0": +"@opentelemetry/api-logs@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/api-logs@npm:0.54.2" dependencies: @@ -13242,67 +13804,76 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.4.0": +"@opentelemetry/api-logs@npm:0.56.0, @opentelemetry/api-logs@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/api-logs@npm:0.56.0" + dependencies: + "@opentelemetry/api": ^1.3.0 + checksum: a6bbad94e638316ef3a6e4835124e6a53c3675f0e9a29bb1a37e7905d38ecb72cba20b4289d0e740d6a7a4b16136ee1b393e55d8c14ade9808b44cfb2533eeea + languageName: node + linkType: hard + +"@opentelemetry/api@npm:^1.3.0, @opentelemetry/api@npm:^1.4.0, @opentelemetry/api@npm:^1.9.0": version: 1.9.0 resolution: "@opentelemetry/api@npm:1.9.0" checksum: 9e88e59d53ced668f3daaecfd721071c5b85a67dd386f1c6f051d1be54375d850016c881f656ffbe9a03bedae85f7e89c2f2b635313f9c9b195ad033cdc31020 languageName: node linkType: hard -"@opentelemetry/auto-instrumentations-node@npm:^0.52.0": - version: 0.52.1 - resolution: "@opentelemetry/auto-instrumentations-node@npm:0.52.1" +"@opentelemetry/auto-instrumentations-node@npm:^0.54.0": + version: 0.54.0 + resolution: "@opentelemetry/auto-instrumentations-node@npm:0.54.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/instrumentation-amqplib": ^0.43.0 - "@opentelemetry/instrumentation-aws-lambda": ^0.47.0 - "@opentelemetry/instrumentation-aws-sdk": ^0.46.0 - "@opentelemetry/instrumentation-bunyan": ^0.42.0 - "@opentelemetry/instrumentation-cassandra-driver": ^0.42.0 - "@opentelemetry/instrumentation-connect": ^0.40.0 - "@opentelemetry/instrumentation-cucumber": ^0.10.0 - "@opentelemetry/instrumentation-dataloader": ^0.13.0 - "@opentelemetry/instrumentation-dns": ^0.40.0 - "@opentelemetry/instrumentation-express": ^0.44.0 - "@opentelemetry/instrumentation-fastify": ^0.41.0 - "@opentelemetry/instrumentation-fs": ^0.16.0 - "@opentelemetry/instrumentation-generic-pool": ^0.40.0 - "@opentelemetry/instrumentation-graphql": ^0.44.0 - "@opentelemetry/instrumentation-grpc": ^0.54.0 - "@opentelemetry/instrumentation-hapi": ^0.42.0 - "@opentelemetry/instrumentation-http": ^0.54.0 - "@opentelemetry/instrumentation-ioredis": ^0.44.0 - "@opentelemetry/instrumentation-kafkajs": ^0.4.0 - "@opentelemetry/instrumentation-knex": ^0.41.0 - "@opentelemetry/instrumentation-koa": ^0.44.0 - "@opentelemetry/instrumentation-lru-memoizer": ^0.41.0 - "@opentelemetry/instrumentation-memcached": ^0.40.0 - "@opentelemetry/instrumentation-mongodb": ^0.48.0 - "@opentelemetry/instrumentation-mongoose": ^0.43.0 - "@opentelemetry/instrumentation-mysql": ^0.42.0 - "@opentelemetry/instrumentation-mysql2": ^0.42.1 - "@opentelemetry/instrumentation-nestjs-core": ^0.41.0 - "@opentelemetry/instrumentation-net": ^0.40.0 - "@opentelemetry/instrumentation-pg": ^0.47.1 - "@opentelemetry/instrumentation-pino": ^0.43.0 - "@opentelemetry/instrumentation-redis": ^0.43.0 - "@opentelemetry/instrumentation-redis-4": ^0.43.0 - "@opentelemetry/instrumentation-restify": ^0.42.0 - "@opentelemetry/instrumentation-router": ^0.41.0 - "@opentelemetry/instrumentation-socket.io": ^0.43.0 - "@opentelemetry/instrumentation-tedious": ^0.15.0 - "@opentelemetry/instrumentation-undici": ^0.7.1 - "@opentelemetry/instrumentation-winston": ^0.41.0 - "@opentelemetry/resource-detector-alibaba-cloud": ^0.29.4 - "@opentelemetry/resource-detector-aws": ^1.7.0 - "@opentelemetry/resource-detector-azure": ^0.2.12 - "@opentelemetry/resource-detector-container": ^0.5.0 - "@opentelemetry/resource-detector-gcp": ^0.29.13 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/instrumentation-amqplib": ^0.45.0 + "@opentelemetry/instrumentation-aws-lambda": ^0.49.0 + "@opentelemetry/instrumentation-aws-sdk": ^0.48.0 + "@opentelemetry/instrumentation-bunyan": ^0.44.0 + "@opentelemetry/instrumentation-cassandra-driver": ^0.44.0 + "@opentelemetry/instrumentation-connect": ^0.42.0 + "@opentelemetry/instrumentation-cucumber": ^0.12.0 + "@opentelemetry/instrumentation-dataloader": ^0.15.0 + "@opentelemetry/instrumentation-dns": ^0.42.0 + "@opentelemetry/instrumentation-express": ^0.46.0 + "@opentelemetry/instrumentation-fastify": ^0.43.0 + "@opentelemetry/instrumentation-fs": ^0.18.0 + "@opentelemetry/instrumentation-generic-pool": ^0.42.0 + "@opentelemetry/instrumentation-graphql": ^0.46.0 + "@opentelemetry/instrumentation-grpc": ^0.56.0 + "@opentelemetry/instrumentation-hapi": ^0.44.0 + "@opentelemetry/instrumentation-http": ^0.56.0 + "@opentelemetry/instrumentation-ioredis": ^0.46.0 + "@opentelemetry/instrumentation-kafkajs": ^0.6.0 + "@opentelemetry/instrumentation-knex": ^0.43.0 + "@opentelemetry/instrumentation-koa": ^0.46.0 + "@opentelemetry/instrumentation-lru-memoizer": ^0.43.0 + "@opentelemetry/instrumentation-memcached": ^0.42.0 + "@opentelemetry/instrumentation-mongodb": ^0.50.0 + "@opentelemetry/instrumentation-mongoose": ^0.45.0 + "@opentelemetry/instrumentation-mysql": ^0.44.0 + "@opentelemetry/instrumentation-mysql2": ^0.44.0 + "@opentelemetry/instrumentation-nestjs-core": ^0.43.0 + "@opentelemetry/instrumentation-net": ^0.42.0 + "@opentelemetry/instrumentation-pg": ^0.49.0 + "@opentelemetry/instrumentation-pino": ^0.45.0 + "@opentelemetry/instrumentation-redis": ^0.45.0 + "@opentelemetry/instrumentation-redis-4": ^0.45.0 + "@opentelemetry/instrumentation-restify": ^0.44.0 + "@opentelemetry/instrumentation-router": ^0.43.0 + "@opentelemetry/instrumentation-socket.io": ^0.45.0 + "@opentelemetry/instrumentation-tedious": ^0.17.0 + "@opentelemetry/instrumentation-undici": ^0.9.0 + "@opentelemetry/instrumentation-winston": ^0.43.0 + "@opentelemetry/resource-detector-alibaba-cloud": ^0.29.6 + "@opentelemetry/resource-detector-aws": ^1.9.0 + "@opentelemetry/resource-detector-azure": ^0.4.0 + "@opentelemetry/resource-detector-container": ^0.5.2 + "@opentelemetry/resource-detector-gcp": ^0.31.0 "@opentelemetry/resources": ^1.24.0 - "@opentelemetry/sdk-node": ^0.54.0 + "@opentelemetry/sdk-node": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.4.1 - checksum: bcff9f9f9c2d118c4cb18b5bb671257a5ec2c445dd8663f4184919488203b672c18085bf7121541c01a29dcbf2f96cbac7248d986d779f694f59abd06c7158ab + checksum: a8f5fe11d4b5090de584b9780dd8358834db8e4ea9dfa12b21c3fe021471b198354f3416a1cf7c6621cae95199d1d1553b7ae7d5f69044d44f767942a90492dc languageName: node linkType: hard @@ -13315,7 +13886,16 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/core@npm:1.27.0, @opentelemetry/core@npm:^1.0.0, @opentelemetry/core@npm:^1.1.0, @opentelemetry/core@npm:^1.25.0, @opentelemetry/core@npm:^1.25.1, @opentelemetry/core@npm:^1.26.0, @opentelemetry/core@npm:^1.8.0": +"@opentelemetry/context-async-hooks@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/context-async-hooks@npm:1.29.0" + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: edbd8d20cee2adaec276e4ec723dca023036c004eccc8bfbfff59e9a8a25a196b05540ed33813f30f9b6e51bc8e51b3de95c927157e874cfaa6510af00d9cf0e + languageName: node + linkType: hard + +"@opentelemetry/core@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/core@npm:1.27.0" dependencies: @@ -13326,6 +13906,17 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/core@npm:1.29.0, @opentelemetry/core@npm:^1.0.0, @opentelemetry/core@npm:^1.1.0, @opentelemetry/core@npm:^1.25.0, @opentelemetry/core@npm:^1.25.1, @opentelemetry/core@npm:^1.26.0, @opentelemetry/core@npm:^1.8.0": + version: 1.29.0 + resolution: "@opentelemetry/core@npm:1.29.0" + dependencies: + "@opentelemetry/semantic-conventions": 1.28.0 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: bf025473175ceee9a64c6d31f01f7d9924b54ebcb603b38dae56d2ef664acb5fe43f393ae9b0aff41deb3a80b7222b74b9fd2764712db30ee2547280aecff509 + languageName: node + linkType: hard + "@opentelemetry/exporter-logs-otlp-grpc@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-logs-otlp-grpc@npm:0.54.2" @@ -13341,6 +13932,21 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-logs-otlp-grpc@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-logs-otlp-grpc@npm:0.56.0" + dependencies: + "@grpc/grpc-js": ^1.7.1 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-grpc-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/sdk-logs": 0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 107336fd62fc917bc75b745b219bff7ea5410e4688f2621c1f8bf05af57275113e64ecc3af23ff843afb1cc44fb4112f96c79b135b5246a6bad2a01c93c7938d + languageName: node + linkType: hard + "@opentelemetry/exporter-logs-otlp-http@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-logs-otlp-http@npm:0.54.2" @@ -13356,6 +13962,21 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-logs-otlp-http@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-logs-otlp-http@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/sdk-logs": 0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 538c05f27821c447fe0463e159ee526baae6978393fe630943d415c115e6db8132c028ed82eaa0f4001e7418697870919b641696b89e355f2567b16323eff732 + languageName: node + linkType: hard + "@opentelemetry/exporter-logs-otlp-proto@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-logs-otlp-proto@npm:0.54.2" @@ -13373,6 +13994,23 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-logs-otlp-proto@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-logs-otlp-proto@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-logs": 0.56.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 77737c7007ee6f062f854b267044bca6d2fd8a19128771834fe943a3e1597aba5931f83ceb6c9ff2375ddc8a6b94ed67a92132396ef3ddd9e7e4db2c1f2864f3 + languageName: node + linkType: hard + "@opentelemetry/exporter-prometheus@npm:^0.54.0": version: 0.54.2 resolution: "@opentelemetry/exporter-prometheus@npm:0.54.2" @@ -13402,6 +14040,22 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-trace-otlp-grpc@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-trace-otlp-grpc@npm:0.56.0" + dependencies: + "@grpc/grpc-js": ^1.7.1 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-grpc-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 90501836c2c300ef47fcbe3fa5af46f6868de658f0f64a72f2fd115639c6673bf8fd7a24a537ba7a402313727136deeeefe8f97ff93453370f0f1ee7d80ef1e5 + languageName: node + linkType: hard + "@opentelemetry/exporter-trace-otlp-http@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.54.2" @@ -13417,6 +14071,21 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-trace-otlp-http@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-trace-otlp-http@npm:0.56.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 4d436ab37c0c5a35e602fa418d69d8830bf4d8e99487206b178e1351a2db7f2a83fd31407e1517ed6dba8c7589d336604d7f44f5f3d30394a13956188d15fee5 + languageName: node + linkType: hard + "@opentelemetry/exporter-trace-otlp-proto@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/exporter-trace-otlp-proto@npm:0.54.2" @@ -13432,6 +14101,21 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/exporter-trace-otlp-proto@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/exporter-trace-otlp-proto@npm:0.56.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: e0e94aa50326fa78fd6fa1b8f2c05ad15b6a3a920fd61a13895a9cef935359221b87af233a053cbc3bbc7296ca96aa5dc242dda0aa93b70d291db7fe5580fc8a + languageName: node + linkType: hard + "@opentelemetry/exporter-zipkin@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/exporter-zipkin@npm:1.27.0" @@ -13446,514 +14130,512 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/instrumentation-amqplib@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-amqplib@npm:0.43.0" +"@opentelemetry/exporter-zipkin@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/exporter-zipkin@npm:1.29.0" dependencies: - "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/semantic-conventions": ^1.27.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + "@opentelemetry/semantic-conventions": 1.28.0 peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 5eb17469d5c3ce2e8495d7e97684cd3b85d1e6aed4081ec1e4103f90bb5ef64633a6913844c5f0afecc2485f77c5b1adfe34c80ed5b7ea48873d9f92b9d04ef2 + "@opentelemetry/api": ^1.0.0 + checksum: 6455c96f28a1f6275459c513fab905c602cc60921cccd4b506050a242145bff5ce2a81268cc1c5531eb238de565cfa54c320231cdfa4bc1a6be6eb31517780a5 languageName: node linkType: hard -"@opentelemetry/instrumentation-aws-lambda@npm:^0.47.0": - version: 0.47.0 - resolution: "@opentelemetry/instrumentation-aws-lambda@npm:0.47.0" +"@opentelemetry/instrumentation-amqplib@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-amqplib@npm:0.45.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/core": ^1.8.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/semantic-conventions": ^1.27.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 3b009e67974f25c37265cbff30ab39e66b46852778e038197c228178f3ac5e6dfab647a24621f5f8aa9f4f1633ad6257c9f7a3638d957d9d81503c1f43179023 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-aws-lambda@npm:^0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-aws-lambda@npm:0.49.0" + dependencies: + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@types/aws-lambda": 8.10.143 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 72925ac1c5d5de107342bf859e0aa5c43b4cda7191b2b0489a7a17ddb3fd7e831a53ee2d20c9d4331918ecf290563d6e4927fa445091b2828d27c2254de05ba3 + checksum: 8f18748d606bd6d6a32fadcee5e127e939a48e8aac49de0edbe1dac61094c4dcabce6457f306c81c527c5c014abdbeb736b95be43c6312e77dffff5c90a68592 languageName: node linkType: hard -"@opentelemetry/instrumentation-aws-sdk@npm:^0.46.0": - version: 0.46.0 - resolution: "@opentelemetry/instrumentation-aws-sdk@npm:0.46.0" +"@opentelemetry/instrumentation-aws-sdk@npm:^0.48.0": + version: 0.48.0 + resolution: "@opentelemetry/instrumentation-aws-sdk@npm:0.48.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/propagation-utils": ^0.30.12 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/propagation-utils": ^0.30.14 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 8e797ab8e8e976c7a87f7ac44c8e132079bbd0e0822b2a1a9596ca62ddfccffb2feb18b0cb63c52a3eeca83fcf0c03fc6cd3210d1bbf07138e6aee2ac273d2c3 + checksum: 0538f38b42a6cd7279ab6f9c85af19525b463a9873fd429163c30ddf817ed17916ab6a53ea05c034d8e6861d10bb031c7ebcbf607b49e3e3c4b89e589a381576 languageName: node linkType: hard -"@opentelemetry/instrumentation-bunyan@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-bunyan@npm:0.42.0" +"@opentelemetry/instrumentation-bunyan@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-bunyan@npm:0.44.0" dependencies: - "@opentelemetry/api-logs": ^0.54.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/api-logs": ^0.56.0 + "@opentelemetry/instrumentation": ^0.56.0 "@types/bunyan": 1.8.9 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 476850eff4e5c2864b0512c014db71a01372e5cce97e870b915450193f5eaee2cec294cdd32340cf5394cf40de3209ccfb47298630d8e3131572e6f0f568a964 + checksum: 4d176289ffbc26e268c24995c385349d4a817abdc1104eea8bc97d5abd7d6e105cc3dd9f69ac568d1094ec33992597a2b8666b94dbfc1e3d9d3e8f103dafb007 languageName: node linkType: hard -"@opentelemetry/instrumentation-cassandra-driver@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-cassandra-driver@npm:0.42.0" +"@opentelemetry/instrumentation-cassandra-driver@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-cassandra-driver@npm:0.44.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: fa9139efc7cb10702cc71aba388d8efdd8a08bbab37864c28f61fb20c1cfa47dd79131a02571231ae14245b2d37bd53877fd359ffe61f86db99117532910f213 + checksum: b4c809a3abd7ddefe14345da1a287958cc80de1470e72232363cf03467e1dbd4a99dc081361fea1472040e5e9ca9c377f997af3782c1ba32121bdb76a5966b60 languageName: node linkType: hard -"@opentelemetry/instrumentation-connect@npm:^0.40.0": - version: 0.40.0 - resolution: "@opentelemetry/instrumentation-connect@npm:0.40.0" +"@opentelemetry/instrumentation-connect@npm:^0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-connect@npm:0.42.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@types/connect": 3.4.36 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 3fe2f82105abc740c813765594f0cce37cbcced2610ac2d48d97311e2bc853695c4953cedb88ed620c163e39492f4549476b3fa1b2b65034abd0fd5b2a1bb1b2 + checksum: 45c749871feedf8af72de48968027005ab560d73054e55da3426f3091a422b9646fd0170ea5b597d4abd4efc585e2e2a6f9e91253d7fb38dccd42f486cb3ea30 languageName: node linkType: hard -"@opentelemetry/instrumentation-cucumber@npm:^0.10.0": - version: 0.10.0 - resolution: "@opentelemetry/instrumentation-cucumber@npm:0.10.0" +"@opentelemetry/instrumentation-cucumber@npm:^0.12.0": + version: 0.12.0 + resolution: "@opentelemetry/instrumentation-cucumber@npm:0.12.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: a6c516b7a301141741a1e74d1e674434bdc99fa381217889dbcf2a03a2d8269a92cdb8517f25bda80b73019d30970980a98f859eb23e5ba10fbb5c899cdc7bf1 + checksum: 2976f1b5ac2b6d218db4b64c173c25ccc4f2230ecfdc934223f1e27ba0cab2aeee8a0ed344646b001610898bf60aa0cd94ada3e1a05a688b6a4980db2d94b11b languageName: node linkType: hard -"@opentelemetry/instrumentation-dataloader@npm:^0.13.0": - version: 0.13.0 - resolution: "@opentelemetry/instrumentation-dataloader@npm:0.13.0" +"@opentelemetry/instrumentation-dataloader@npm:^0.15.0": + version: 0.15.0 + resolution: "@opentelemetry/instrumentation-dataloader@npm:0.15.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: f423888d71c9b15c02dce863cccb5fa677c625bd3b864ba545be368275e3f88b03284073a24f7f3cb4c0c1f3544c92580b53abdf15dd098fd33c60c6d8326c24 + checksum: a1f217be8064be3cbd116c0fb58feef46b6e05fe9ac3c0333d5cc43ac9df182550bb8f5b084e9557f73e0af7fe917a81d79d69f640009ef64624b97e17f1bb85 languageName: node linkType: hard -"@opentelemetry/instrumentation-dns@npm:^0.40.0": - version: 0.40.0 - resolution: "@opentelemetry/instrumentation-dns@npm:0.40.0" - dependencies: - "@opentelemetry/instrumentation": ^0.54.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: dbc1a4b31b3fe78c46cd19c76162dedec175d07d09d6a553d9b31560ceab4ee6781ca88e5246fd9b371260bfa48c8ab26640d3e5ac914d4d6e8284214a7f86de - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-express@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-express@npm:0.44.0" - dependencies: - "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/semantic-conventions": ^1.27.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 0ab8be80c817021b7a96fa94bf55c635fa664d2c03058e1485311f4f4bf964e5cf7756185c9003a4d59ac6fc766eff52a7b390a91ca3946ce3d371f3135ea4d5 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-fastify@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-fastify@npm:0.41.0" - dependencies: - "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/semantic-conventions": ^1.27.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: dc790cd6ee7ea2322be2e35ce259e10a1f42827970b0b83a6ca7a5a934a986dea7239fe1a29cc772529c1504f24d3afe91c0923a87efc12e8ea1b1321df18514 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-fs@npm:^0.16.0": - version: 0.16.0 - resolution: "@opentelemetry/instrumentation-fs@npm:0.16.0" - dependencies: - "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: d74b3ab430c909b7840322540ab51664c29e8ff43fd4eaa77edf11828e5b2234b519771f8d64d051d6a508c1c20c377e606f032fa758ef08eb23e0336e3746bc - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-generic-pool@npm:^0.40.0": - version: 0.40.0 - resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.40.0" - dependencies: - "@opentelemetry/instrumentation": ^0.54.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 665d687191983bd756db1e510b604e244100c42fa6667d7512d42d58a2d319d114d41c96ada15cfa3344763022774138acaee1bec43fdbbfae5aa5bc65a72e0a - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-graphql@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-graphql@npm:0.44.0" - dependencies: - "@opentelemetry/instrumentation": ^0.54.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: c4f0f771e1d939de844a97b0e5c0416d5c0d12d2d94e369566b61ec3819193c7eb113c9b3101581c83bb44bdb2b289a33623488ab7446be370e3577ebe37a198 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-grpc@npm:^0.54.0": - version: 0.54.1 - resolution: "@opentelemetry/instrumentation-grpc@npm:0.54.1" - dependencies: - "@opentelemetry/instrumentation": 0.54.1 - "@opentelemetry/semantic-conventions": 1.27.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: fc85c6d1f93f4e0a9368c458b4569c0e60f86976f22c9e9a9d903f79079f93b5a280f3ab14b548149984241e5efd6d04f9b5018709e1377159c3cd41d3a08495 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-hapi@npm:^0.42.0": +"@opentelemetry/instrumentation-dns@npm:^0.42.0": version: 0.42.0 - resolution: "@opentelemetry/instrumentation-hapi@npm:0.42.0" + resolution: "@opentelemetry/instrumentation-dns@npm:0.42.0" dependencies: - "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/semantic-conventions": ^1.27.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 4e755b3ad4426820d6172f01cd603f14ac75a4521292d912cd31eeaef3e5aa0b9caad5a617b2543a07824b5e385c9bbf256a45acc8a66127096cae03fc48a20d + checksum: 4717331b7429c5a427eb48d7ebd210584806bf672b71dde0bacf677488e39a201a593f3ac16ef7a7ce1ed75cc37e6ea5daff9dccfcd2ec79f09808b77ad55352 languageName: node linkType: hard -"@opentelemetry/instrumentation-http@npm:^0.54.0": - version: 0.54.1 - resolution: "@opentelemetry/instrumentation-http@npm:0.54.1" +"@opentelemetry/instrumentation-express@npm:^0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-express@npm:0.46.0" dependencies: - "@opentelemetry/core": 1.27.0 - "@opentelemetry/instrumentation": 0.54.1 - "@opentelemetry/semantic-conventions": 1.27.0 + "@opentelemetry/core": ^1.8.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/semantic-conventions": ^1.27.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 799938a06ded695d9e5f32f902d5f6d960e6756ec2d09f34b2373d74a441ea0b9dfeed6f0c1668cf97c9b33991a724fe5be8dec328f0c8cacc0ac8507df10687 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-fastify@npm:^0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-fastify@npm:0.43.0" + dependencies: + "@opentelemetry/core": ^1.8.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/semantic-conventions": ^1.27.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 008c6f2567ecabe69552f78f8fbcefdf2492d85b0e3e0ac36bd47e6f13a8d02680e7cee1748cd4a70ca9f27213abd30c28bf14d7791ead8a06bf1c85986ef7f9 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-fs@npm:^0.18.0": + version: 0.18.0 + resolution: "@opentelemetry/instrumentation-fs@npm:0.18.0" + dependencies: + "@opentelemetry/core": ^1.8.0 + "@opentelemetry/instrumentation": ^0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 2fe2694f5dd4ef9bfe7b75e66655cbde93afe2bb4f55731841b8ec5ac5af18912d4428edfe6901806452442060262edef14e46719f1faf85e5f11bb0274a054b + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-generic-pool@npm:^0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-generic-pool@npm:0.42.0" + dependencies: + "@opentelemetry/instrumentation": ^0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 5f35a30b76705f4527f0ab8ec83d83014615612f40a7bd16a87a75f922a7aeff113042ae99d30f7ab809853841d2769ddee2e03ce304de80251f1d8370ec2d89 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-graphql@npm:^0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-graphql@npm:0.46.0" + dependencies: + "@opentelemetry/instrumentation": ^0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: b8c9faa2c002846bf85a4ccf4e9aba343d8f38a08e85d8c4e77a016da2d0b84291d6b8505aec7de70088761d4a341192a26163aafc23a2fc04a918c94c1686b6 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-grpc@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation-grpc@npm:0.56.0" + dependencies: + "@opentelemetry/instrumentation": 0.56.0 + "@opentelemetry/semantic-conventions": 1.28.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 8bb00759e74d05bc7ca3ba7c46fe6ab01ff16adcb5c658a3e1679c5ea6d10b0f381ffae970a694b014881cbaa707ec24076967fa47643187365b765f34f4094e + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-hapi@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-hapi@npm:0.44.0" + dependencies: + "@opentelemetry/core": ^1.8.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/semantic-conventions": ^1.27.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 0ee7610e9a1149d087dc8883f6d20ed7d0a15c7b1da273fc170220daec5e68a1240e0624743b000c8d263bb8b21615ecf84b8a179508763523108de88fedadb4 + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-http@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation-http@npm:0.56.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/instrumentation": 0.56.0 + "@opentelemetry/semantic-conventions": 1.28.0 forwarded-parse: 2.1.2 semver: ^7.5.2 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 49a1bda0417ef5866398b89114a7f61d9eb040faa338603746af074dab315eca791443b35b9a1fa00d3b176f807b4a88f9003323570d50ee174f8c86cd3614d6 + checksum: f8033d8410d8b06bb222090959479fe4f24c8d52281ce3e240458a449eab8009cb889d09240f67135699b7a543a4708c2f401060cbf1bfa0663ee8687c451a15 languageName: node linkType: hard -"@opentelemetry/instrumentation-ioredis@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-ioredis@npm:0.44.0" +"@opentelemetry/instrumentation-ioredis@npm:^0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-ioredis@npm:0.46.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/redis-common": ^0.36.2 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 774e7cfdf6cd96e6f88a671fdd2d43fdf4591b5e821820971d91cc2b3a83b01c8cf56297fbd5d4578c2b2b8e404c4426222de09198da9915eb6cc9e4b3489636 + checksum: 02a816026d950726562104be37a434b13174fea5120639462a43d70dc011a4c334f402ff5d763a986aa3795d0c9ee9fc200d41ae77b57ea55a4eca14068216f4 languageName: node linkType: hard -"@opentelemetry/instrumentation-kafkajs@npm:^0.4.0": - version: 0.4.0 - resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.4.0" +"@opentelemetry/instrumentation-kafkajs@npm:^0.6.0": + version: 0.6.0 + resolution: "@opentelemetry/instrumentation-kafkajs@npm:0.6.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 23d8d8aa2945f372aaab8ab9a583821339c523d8203090e29652eb90c9600fc273e131d5a0b9464fe09cacde6b35f44e3046effa1b20f936a064872ba18352ec + checksum: 169877945296fa042b5468e25759a67dc81d169a7a4f22ee142e8e9bf0a9d82219397500596060554324f1a9a89c9843ac68633830cec11c99e838fd37d997f5 languageName: node linkType: hard -"@opentelemetry/instrumentation-knex@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-knex@npm:0.41.0" +"@opentelemetry/instrumentation-knex@npm:^0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-knex@npm:0.43.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: c3b463e2b909a1d82a789f7cb5477efd60857f18ffb088903bf4bc06cd237f249e16b29338bebd7c16f72dd49ed61251f57cf81af2cc7708ebf37e628f27eafd + checksum: e31af57cb7f3f24ec5ac0748eba0e785e3bb2bb7ad5cdaec2af1f37a077a73ea4b545521450fb5ddfceff3dd8388abbe660959a43222bb2252a155354c346c0b languageName: node linkType: hard -"@opentelemetry/instrumentation-koa@npm:^0.44.0": - version: 0.44.0 - resolution: "@opentelemetry/instrumentation-koa@npm:0.44.0" +"@opentelemetry/instrumentation-koa@npm:^0.46.0": + version: 0.46.0 + resolution: "@opentelemetry/instrumentation-koa@npm:0.46.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 09d8a87e874d9d5050a5f866fbd9ac90bc432c3934f99f68acc11a3936dc594097c31ba9622afeb4b5fc379a255f6e331b978935b360f918e784b27e1de70234 + checksum: b22a6cc9036b0766b5ea2fd8078944877d22cac916d310123af12f317a78b898039dd3ca788cccfce018ec2f6e6220850573ea006cdce1205dc858526fb6a6f9 languageName: node linkType: hard -"@opentelemetry/instrumentation-lru-memoizer@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.41.0" +"@opentelemetry/instrumentation-lru-memoizer@npm:^0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-lru-memoizer@npm:0.43.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 409c13e0e095fbbfdef0d001b4b881fc1cf470eab97e9c391e51b0f0e185ecfebf2b03487b30aed3aab77ad600944525375fdd276e5b763be7bb1b1903e8a553 + checksum: a7c52fe37c25acab54d64d9d8944477925bce311d08794eb5fbe5e75e7d66ee00585f37c331a489f62947b511b3089b8848ff2de2954a49cc7a1c3cb58dd7ede languageName: node linkType: hard -"@opentelemetry/instrumentation-memcached@npm:^0.40.0": - version: 0.40.0 - resolution: "@opentelemetry/instrumentation-memcached@npm:0.40.0" +"@opentelemetry/instrumentation-memcached@npm:^0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-memcached@npm:0.42.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@types/memcached": ^2.2.6 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: e33438c31ea6482382013603c0a81b2247757fe46fc433dbf7ca9c9577ef61175a7ff7d9a2d1560c0a4b6382616fa3a6bce3c21f82a7072cc5d27b4bb2a14efc + checksum: 80bd1c3d5d14fb738b061dd61ff41950e146797ad18775da862d8e35401335e7506b33d3f9682235e5dcfed2371e4b2fe7cddad3b22aa1db588f47b6356325f9 languageName: node linkType: hard -"@opentelemetry/instrumentation-mongodb@npm:^0.48.0": - version: 0.48.0 - resolution: "@opentelemetry/instrumentation-mongodb@npm:0.48.0" +"@opentelemetry/instrumentation-mongodb@npm:^0.50.0": + version: 0.50.0 + resolution: "@opentelemetry/instrumentation-mongodb@npm:0.50.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 910925d26cf7af63001c483c790deb75365bdeb314ecbf8d84b908eea4d3ecb1025a53b0f86a903c367a538a47756e423d6f697418782dc84d06dff49b483494 + checksum: 4d7c1823a3de297f8c68e1669792fa007028346eeb005103dc66d70a7f0cdb5bce323b97e4e247b7aa50e2a830b1c645ab718da432b319c31f3d714f85f1e629 languageName: node linkType: hard -"@opentelemetry/instrumentation-mongoose@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-mongoose@npm:0.43.0" +"@opentelemetry/instrumentation-mongoose@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-mongoose@npm:0.45.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 2eced33f6262e7eb47113cdbe2d518e719bcfb5f570a195d70f0cdf916baf87165bb527487c9bef8c2d67ae6f963bfb50c98f706b3724d0ebae6c27ec576e965 + checksum: 3288fdaa0bc141609f54fad75275d8e1bfaf55dafdce63dd54db76cf0eb955fdcf1788d475c577156138880120fcc179f55f55b7849636b228d8f482b2aa024c languageName: node linkType: hard -"@opentelemetry/instrumentation-mysql2@npm:^0.42.1": - version: 0.42.1 - resolution: "@opentelemetry/instrumentation-mysql2@npm:0.42.1" +"@opentelemetry/instrumentation-mysql2@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-mysql2@npm:0.44.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@opentelemetry/sql-common": ^0.40.1 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 421f5c44102f74e3439c72bb58a341a69956e8f8f9ea04eb1d5f951003119d4124a23a75509ea2264380bc8c9321579fc24a8424a313c961b5b16365305c0644 + checksum: 72d5b5658d39d5f92ff5b8c1771d8d6ed28979b4d7fb16121dd5a6d76fd231cae364d162bf04a83de3682e149f829766a61c2715eb9959b34ee8ac303cb724c2 languageName: node linkType: hard -"@opentelemetry/instrumentation-mysql@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-mysql@npm:0.42.0" +"@opentelemetry/instrumentation-mysql@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-mysql@npm:0.44.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@types/mysql": 2.15.26 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 27ed48852ede4380499c6fde38103c9e9775b59e3f7f08ff48757eea93308c9305fb5d441bb17ddcd8003bbc35179a4da9a5fd8e6dfcfc855a0dbb83c5e38929 + checksum: a1c55777fef8b8aa349f16a0c5f511bc06f553e6ac1d316a0cd768f49d92d1f75cdabce73d5a2e5590588773bae93521953eb27bf04444105a3727dfd8e10788 languageName: node linkType: hard -"@opentelemetry/instrumentation-nestjs-core@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-nestjs-core@npm:0.41.0" +"@opentelemetry/instrumentation-nestjs-core@npm:^0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-nestjs-core@npm:0.43.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 2fb0365dbc6c6aa83953039698e2df339517bcf797d376e6a0bde2b857dccb1dd5799559cf7f2532f8d794227069663f7fbe0cab2f2e0cddaccc5ad99e74148c + checksum: f967f3f96ce6bf402f5acd9cedefca6f0548bbc786fc849e07a6229c3a7b16ce7b05cd864657ec1af2a8285ea9ea58c4199e8ec2610d115b85db7e4c50a5c1e6 languageName: node linkType: hard -"@opentelemetry/instrumentation-net@npm:^0.40.0": - version: 0.40.0 - resolution: "@opentelemetry/instrumentation-net@npm:0.40.0" +"@opentelemetry/instrumentation-net@npm:^0.42.0": + version: 0.42.0 + resolution: "@opentelemetry/instrumentation-net@npm:0.42.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 88821c24332532f1100fe2b2dd80a5ac5246595a4e5b8d51a8d2909918f8c4cab52a7bba2f9db616ffac268ff44e30a111bc20ac7cc94dd8f55b918b81723383 + checksum: ebad2b908081f1c69a07b14ee273958216845e197d7059bee51eb1a12701c2c1406d6a0ad989c27300b7563166808bb1557a54419850f7c40fecf602ee1132ac languageName: node linkType: hard -"@opentelemetry/instrumentation-pg@npm:^0.47.1": - version: 0.47.1 - resolution: "@opentelemetry/instrumentation-pg@npm:0.47.1" +"@opentelemetry/instrumentation-pg@npm:^0.49.0": + version: 0.49.0 + resolution: "@opentelemetry/instrumentation-pg@npm:0.49.0" dependencies: "@opentelemetry/core": ^1.26.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": 1.27.0 "@opentelemetry/sql-common": ^0.40.1 "@types/pg": 8.6.1 "@types/pg-pool": 2.0.6 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: eec188f1c41456e044842d7aa89f9bb4ba7755906292666949ccb4add37ecad3b28abb17f4f736f72be78ec99b68ad797ba4a57dbfb4c1e07eb18ce5283b8e1d + checksum: a91ab43d5cc3e1ead331125207b1447edcfb9cfc13a7b3eced2b9965236b3b76bdbe43dc91a634c0253afdfc7996f6286b7e1748c63d82848b64a4d060df19d8 languageName: node linkType: hard -"@opentelemetry/instrumentation-pino@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-pino@npm:0.43.0" +"@opentelemetry/instrumentation-pino@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-pino@npm:0.45.0" dependencies: - "@opentelemetry/api-logs": ^0.54.0 + "@opentelemetry/api-logs": ^0.56.0 "@opentelemetry/core": ^1.25.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 76efd25275edb0159057ac90fc3152dd9e76640a4e4986bbd6065c0d3dd2ece043817260e4230e203dffcf9f962f11f379bb4e35aed95c537679d6c0b026f4d3 + checksum: 4c3393b9bfd60b04baf9640763aa5f2873926384ec243d075fcd5f4000025453aa310cc523f946bc12a464c7aa084f6b8f88dd4bd257450486bd8603b0d2c6d6 languageName: node linkType: hard -"@opentelemetry/instrumentation-redis-4@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-redis-4@npm:0.43.0" +"@opentelemetry/instrumentation-redis-4@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-redis-4@npm:0.45.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/redis-common": ^0.36.2 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: eb0dbedcccaca2a98cdefe741f14613a2de89c53dfd4393bbbfd97b341a2754c7c88d868429754bb9bf3dbcf17c2610d0070898bfe14b4dd9e5830d0f0c2e5f7 + checksum: d6a3f657d4c81c80b83b3c7f95d4d59fcb65dfd56ccc4da12bbe32d67837b6a91aa87d49373302a82dccc9c62a6090fefbcb1bc650e2858a70f3667df7a8ded7 languageName: node linkType: hard -"@opentelemetry/instrumentation-redis@npm:^0.43.0": - version: 0.43.0 - resolution: "@opentelemetry/instrumentation-redis@npm:0.43.0" +"@opentelemetry/instrumentation-redis@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-redis@npm:0.45.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/redis-common": ^0.36.2 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: ce0032edec122cd4feb0cfa5c365098c66858dc462dbb3cf95f36a24321460a1eddbe93552249bc9f43ce1b0692f88e971a2a432c26843d40776340debae48db + checksum: 7e0c9de80bc785c5e8bf83cb21a5647d24b512cd50d82f6b6e7b64267e49cfa02557dddb40eba13ca722dcb634a49ce82e1c9898d17f5fffe7bc3dd768cbb507 languageName: node linkType: hard -"@opentelemetry/instrumentation-restify@npm:^0.42.0": - version: 0.42.0 - resolution: "@opentelemetry/instrumentation-restify@npm:0.42.0" +"@opentelemetry/instrumentation-restify@npm:^0.44.0": + version: 0.44.0 + resolution: "@opentelemetry/instrumentation-restify@npm:0.44.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 19ae0540538b1150b802c03ea4e4cf65c66230518b4396d75e4abf570350ca69b591eb45bc30a3282df4a157057ac5eb85614715d49c7b225f3ae90b6c43e740 + checksum: 98ef2da10c5faa03db17032399565343dd2fbfbb70788cb7112653ed8ebe2a7920ec50416c9a7b406f239b9363e5ec49e8e56519f224ece6e63f4aaa193fc5ed languageName: node linkType: hard -"@opentelemetry/instrumentation-router@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-router@npm:0.41.0" - dependencies: - "@opentelemetry/instrumentation": ^0.54.0 - "@opentelemetry/semantic-conventions": ^1.27.0 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 2291f8f7ab314e0e12d5dcc1ec6efcade2ce662a5e9214390a89689513b6742a4be71227c7076ff49061049a622ba924cb0905198bdd3343a7bb1c02ed3c1a46 - languageName: node - linkType: hard - -"@opentelemetry/instrumentation-socket.io@npm:^0.43.0": +"@opentelemetry/instrumentation-router@npm:^0.43.0": version: 0.43.0 - resolution: "@opentelemetry/instrumentation-socket.io@npm:0.43.0" + resolution: "@opentelemetry/instrumentation-router@npm:0.43.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 1805d39201cb2f00e9765017c4e037faf1fa54d6f6cef2dcbbb5f07e90dc94d694736bbddb8c41b3bc8db0411b7e43b2d1d008342aaaa27302620617622b0ff5 + checksum: c1045bd51631a5d1c4654a0b7c3c4a2ab2c2bca331e840bf16ab31ecf2a34effd3366db44e679c534b51232120f1ae0ea7bf4d04cbdfd3e6ea736a9133d4f348 languageName: node linkType: hard -"@opentelemetry/instrumentation-tedious@npm:^0.15.0": - version: 0.15.0 - resolution: "@opentelemetry/instrumentation-tedious@npm:0.15.0" +"@opentelemetry/instrumentation-socket.io@npm:^0.45.0": + version: 0.45.0 + resolution: "@opentelemetry/instrumentation-socket.io@npm:0.45.0" dependencies: - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 + "@opentelemetry/semantic-conventions": ^1.27.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 0849eb3118ba223aaff324eda86d5b519e85ba24d66c1027dbd2e669fe94ee05d7f292f10e9ef8aa85b96e7e4bcb6934d796a3380c3e2835240d772df69806ce + languageName: node + linkType: hard + +"@opentelemetry/instrumentation-tedious@npm:^0.17.0": + version: 0.17.0 + resolution: "@opentelemetry/instrumentation-tedious@npm:0.17.0" + dependencies: + "@opentelemetry/instrumentation": ^0.56.0 "@opentelemetry/semantic-conventions": ^1.27.0 "@types/tedious": ^4.0.14 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 75ece9a359c81cdf31eb3e16be570418775817ff2b7b315e49fcc5d2365f635e0fb2af734de029f4d2faa720c3d977325d5e636d69008fb64b53afb6544bb67f + checksum: d4179b6d2010455cb00abf4a64d2276b10db8d572bf15454d62d458a9ca4b54a9df29d16fb455b3936868f5f64b2f69c8112d467efcf02e447172c0d2caa6f22 languageName: node linkType: hard -"@opentelemetry/instrumentation-undici@npm:^0.7.1": - version: 0.7.1 - resolution: "@opentelemetry/instrumentation-undici@npm:0.7.1" +"@opentelemetry/instrumentation-undici@npm:^0.9.0": + version: 0.9.0 + resolution: "@opentelemetry/instrumentation-undici@npm:0.9.0" dependencies: "@opentelemetry/core": ^1.8.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.7.0 - checksum: a086224407d814c3a7476a09be8ec5b46ea743d21583821381a8efc4e12a05091c5bab4a6738b8019a01df71026afdd4243830615ec21ba261d3b1df07444cf8 + checksum: f64615394a511e1aeb88a2095940832b9f6bfa1244c8736234b9a4108da81d227cf8a7218216df30333918cc07b336fe8559fb127de6afc2cbfaa5ed7a49ee86 languageName: node linkType: hard -"@opentelemetry/instrumentation-winston@npm:^0.41.0": - version: 0.41.0 - resolution: "@opentelemetry/instrumentation-winston@npm:0.41.0" +"@opentelemetry/instrumentation-winston@npm:^0.43.0": + version: 0.43.0 + resolution: "@opentelemetry/instrumentation-winston@npm:0.43.0" dependencies: - "@opentelemetry/api-logs": ^0.54.0 - "@opentelemetry/instrumentation": ^0.54.0 + "@opentelemetry/api-logs": ^0.56.0 + "@opentelemetry/instrumentation": ^0.56.0 peerDependencies: "@opentelemetry/api": ^1.3.0 - checksum: 10d2769925ae9a9982c8da9bb81c6e121f9c1c3437ac99216eb8c68fddea8a3527b5f9acfb09275646e3bc05183bf5bd2b719576756fa40ea3b98a6950a7533f + checksum: f8eafb7d943956f8daf0b432fce421fd85ac910f499f9bb6ec6fe048caafa33705d793c6fe8c6c969ba22951f888553f8862bef13f1cae78ef43d8f402173785 languageName: node linkType: hard -"@opentelemetry/instrumentation@npm:0.54.1": - version: 0.54.1 - resolution: "@opentelemetry/instrumentation@npm:0.54.1" - dependencies: - "@opentelemetry/api-logs": 0.54.1 - "@types/shimmer": ^1.2.0 - import-in-the-middle: ^1.8.1 - require-in-the-middle: ^7.1.1 - semver: ^7.5.2 - shimmer: ^1.2.1 - peerDependencies: - "@opentelemetry/api": ^1.3.0 - checksum: 3109540b953aa8d06c8e57882c9af240be475a28d7a3245de8d93667997e70c2a528b72f75af8faaa82436690068aa8a6caaa65ca0aa329429d0b3c9ae6e703e - languageName: node - linkType: hard - -"@opentelemetry/instrumentation@npm:0.54.2, @opentelemetry/instrumentation@npm:^0.54.0": +"@opentelemetry/instrumentation@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/instrumentation@npm:0.54.2" dependencies: @@ -13969,6 +14651,22 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/instrumentation@npm:0.56.0, @opentelemetry/instrumentation@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/instrumentation@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@types/shimmer": ^1.2.0 + import-in-the-middle: ^1.8.1 + require-in-the-middle: ^7.1.1 + semver: ^7.5.2 + shimmer: ^1.2.1 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 2c0cf2c91a5ac36a9e95978bfcc92ed9e770d93346fb87cc6e62ca7e028b219695e921142eef3ff5541bdfb9045996817bd7cefdb668e0419a27abde4854d2e0 + languageName: node + linkType: hard + "@opentelemetry/otlp-exporter-base@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/otlp-exporter-base@npm:0.54.2" @@ -13981,6 +14679,18 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/otlp-exporter-base@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/otlp-exporter-base@npm:0.56.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-transformer": 0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 19537be39eed2969003f244de9f0616af5fae4dbfceaf24918b9f051ab906817f1c32a657d9b548c4c24742eb45c48a21b75cd2bee0b33068cedb0b592a002ae + languageName: node + linkType: hard + "@opentelemetry/otlp-grpc-exporter-base@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/otlp-grpc-exporter-base@npm:0.54.2" @@ -13995,6 +14705,20 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/otlp-grpc-exporter-base@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/otlp-grpc-exporter-base@npm:0.56.0" + dependencies: + "@grpc/grpc-js": ^1.7.1 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/otlp-exporter-base": 0.56.0 + "@opentelemetry/otlp-transformer": 0.56.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: d2188bd77c192df2a72cdf2bc3e219da26b599e03eb4ca32ab76eac83419ddb0729efe472e756a0c00500a071e10940d0f06e63ff879ced5204cce4213ba2598 + languageName: node + linkType: hard + "@opentelemetry/otlp-transformer@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/otlp-transformer@npm:0.54.2" @@ -14012,12 +14736,29 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/propagation-utils@npm:^0.30.12": - version: 0.30.12 - resolution: "@opentelemetry/propagation-utils@npm:0.30.12" +"@opentelemetry/otlp-transformer@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/otlp-transformer@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-logs": 0.56.0 + "@opentelemetry/sdk-metrics": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + protobufjs: ^7.3.0 + peerDependencies: + "@opentelemetry/api": ^1.3.0 + checksum: 3b95605194f126be450fd7b5a7522a08bb563f716a43c863e21f7c5e4175101833a94d8f0955e1181ce75211e2b2acfe8691efd0302afa7b41d8b26ddaba3a10 + languageName: node + linkType: hard + +"@opentelemetry/propagation-utils@npm:^0.30.14": + version: 0.30.14 + resolution: "@opentelemetry/propagation-utils@npm:0.30.14" peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 1bf6b1a9d00ab0950768f4acb2ccf888592aecfcffde1554b55ffd28c50025920de2725c20f07307b8f4c189c95c413f74b84edb088df3e1d8ce182e83b5cf36 + checksum: 2f7ddc71d39b4d095973087b437191d276fea341750d8e1843da230f83bef9779ca61fe70515bb7a8b8e45671d069ce910ad0d578110860cf08b211fc514801a languageName: node linkType: hard @@ -14032,6 +14773,17 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/propagator-b3@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/propagator-b3@npm:1.29.0" + dependencies: + "@opentelemetry/core": 1.29.0 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 36720d2f4572c45d80149dda1cf1000cd6da8baf7bf1679fa4a58b000668837133b9ab9d8fad93af4752bcc14946364a41ad5e71c0262e4dcdcb43926132df6d + languageName: node + linkType: hard + "@opentelemetry/propagator-jaeger@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/propagator-jaeger@npm:1.27.0" @@ -14043,6 +14795,17 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/propagator-jaeger@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/propagator-jaeger@npm:1.29.0" + dependencies: + "@opentelemetry/core": 1.29.0 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: eb19ad74c16ef2bd7805f06cf3c6e5ab654889c49221678be75933c45f47d6b496343947b364ec57860d8d9432ce5542d6ac43f8bd0d153b9b47f251abff6653 + languageName: node + linkType: hard + "@opentelemetry/redis-common@npm:^0.36.2": version: 0.36.2 resolution: "@opentelemetry/redis-common@npm:0.36.2" @@ -14050,61 +14813,61 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/resource-detector-alibaba-cloud@npm:^0.29.4": - version: 0.29.4 - resolution: "@opentelemetry/resource-detector-alibaba-cloud@npm:0.29.4" +"@opentelemetry/resource-detector-alibaba-cloud@npm:^0.29.6": + version: 0.29.6 + resolution: "@opentelemetry/resource-detector-alibaba-cloud@npm:0.29.6" dependencies: "@opentelemetry/core": ^1.26.0 "@opentelemetry/resources": ^1.10.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 78d4100e8dfb814a6ea35c2b9ef12fd93d402ffab93d7a592f3c2d486392e281cd751c2312482e75440eab3a6cd235866c5b14993bf6f6a12a9f3ade91ed3539 + checksum: d8cef13063b0e674fb581312c4fdeab41c95829d72f8a0971e49a8ea667fcd0bd235fb6e44f248412205bf9dfb8c307aeb3af11ade482f19864e0b4eb16d863d languageName: node linkType: hard -"@opentelemetry/resource-detector-aws@npm:^1.7.0": - version: 1.7.0 - resolution: "@opentelemetry/resource-detector-aws@npm:1.7.0" +"@opentelemetry/resource-detector-aws@npm:^1.9.0": + version: 1.9.0 + resolution: "@opentelemetry/resource-detector-aws@npm:1.9.0" dependencies: "@opentelemetry/core": ^1.0.0 "@opentelemetry/resources": ^1.10.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: cbe754b5ea525064478e572a73d05979f6bc8d9bf5b063d3ea104545f0e50e04fbc0ae1376bb2543262d20ef2aad9388b1ff0e485d96ac1446efbc542ab8d818 + checksum: 11d8a3a4ffb66124f420f800488dfb1e46eed3ff9328693ee47b5ba65638c4f2ac16ac2b6e9edcd271d1a35bcc9044766daa17754d9f95f1ebbba10ec63507e4 languageName: node linkType: hard -"@opentelemetry/resource-detector-azure@npm:^0.2.12": - version: 0.2.12 - resolution: "@opentelemetry/resource-detector-azure@npm:0.2.12" +"@opentelemetry/resource-detector-azure@npm:^0.4.0": + version: 0.4.0 + resolution: "@opentelemetry/resource-detector-azure@npm:0.4.0" dependencies: "@opentelemetry/core": ^1.25.1 "@opentelemetry/resources": ^1.10.1 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: b0a170ac928248021ea6b63bea1f25d670bb3c2a0260eae115097d84461732ff602a65f56ef84651ae1e70be3e9729ae5068c3038732a009ec2e3a2d1eccce40 + checksum: 1dce98349bc0bcaaf933f8e243026bb7d93f872ce08f3bd214ecc0125dad27afd84b607f0aae50c18316d10efa755c7e8c0b71a5a728408dacee71df2c8f02f6 languageName: node linkType: hard -"@opentelemetry/resource-detector-container@npm:^0.5.0": - version: 0.5.0 - resolution: "@opentelemetry/resource-detector-container@npm:0.5.0" +"@opentelemetry/resource-detector-container@npm:^0.5.2": + version: 0.5.2 + resolution: "@opentelemetry/resource-detector-container@npm:0.5.2" dependencies: "@opentelemetry/core": ^1.26.0 "@opentelemetry/resources": ^1.10.0 "@opentelemetry/semantic-conventions": ^1.27.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 912762621d55ddffe69b6ba3f5c470cbb9bf3a465303d9f3ab542d9fd2dbe660927cb173783397b47f11588f60c66ec06ff1572d7bcf72ff6da10bc4f1fdd4d0 + checksum: 7d09a68f0e6f3f455f075e499eb5229f8f561124813b55a727e17d7de7c430470906634d97265a365971ffec67c70f0a3271b4e6c25ade8a65a48f9668c67c68 languageName: node linkType: hard -"@opentelemetry/resource-detector-gcp@npm:^0.29.13": - version: 0.29.13 - resolution: "@opentelemetry/resource-detector-gcp@npm:0.29.13" +"@opentelemetry/resource-detector-gcp@npm:^0.31.0": + version: 0.31.0 + resolution: "@opentelemetry/resource-detector-gcp@npm:0.31.0" dependencies: "@opentelemetry/core": ^1.0.0 "@opentelemetry/resources": ^1.10.0 @@ -14112,11 +14875,11 @@ __metadata: gcp-metadata: ^6.0.0 peerDependencies: "@opentelemetry/api": ^1.0.0 - checksum: 64d6995f3775a599985e5787276d81f1aeefa3352017965a797c3b33196f155eb3886633d1b22974aa1cae7425eff9229b4b8c0eb9ed7a454e50e1f94f1fed31 + checksum: d62de94728ca67f03d9aa75a8a291285061cb058a8f245c2ca7b4a8e92e8c480e9958cc9dfd4550ba39475c5f06e0a692e19f6c0762f02005b617622082e3cc1 languageName: node linkType: hard -"@opentelemetry/resources@npm:1.27.0, @opentelemetry/resources@npm:^1.10.0, @opentelemetry/resources@npm:^1.10.1, @opentelemetry/resources@npm:^1.24.0": +"@opentelemetry/resources@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/resources@npm:1.27.0" dependencies: @@ -14128,6 +14891,18 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/resources@npm:1.29.0, @opentelemetry/resources@npm:^1.10.0, @opentelemetry/resources@npm:^1.10.1, @opentelemetry/resources@npm:^1.24.0": + version: 1.29.0 + resolution: "@opentelemetry/resources@npm:1.29.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/semantic-conventions": 1.28.0 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: dfa68245089fe4eb8983503539e2109753fd232d769f8bba675c3277ababde88b4e7d60af7ed34a7529a021af0f0df457e3782563597a58ba0599f0161b502b2 + languageName: node + linkType: hard + "@opentelemetry/sdk-logs@npm:0.54.2": version: 0.54.2 resolution: "@opentelemetry/sdk-logs@npm:0.54.2" @@ -14141,6 +14916,19 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/sdk-logs@npm:0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/sdk-logs@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/resources": 1.29.0 + peerDependencies: + "@opentelemetry/api": ">=1.4.0 <1.10.0" + checksum: f0aed974f93a1b4e21a8d8a4fdc1ae87defe1f7b45dc58f56bb5d7bd41d0dc400ca9bb28af72b193baa4ddef4a1ec1168aee17aa4bf62c58caf1070e521ddfe2 + languageName: node + linkType: hard + "@opentelemetry/sdk-metrics@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/sdk-metrics@npm:1.27.0" @@ -14153,6 +14941,18 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/sdk-metrics@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/sdk-metrics@npm:1.29.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/resources": 1.29.0 + peerDependencies: + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: 036f2da0adff7ffd69cd2b7892b81ef4dcd0caa0c3d176dbfec9282a004f56af46956b66949f8e3ce27db589c99fa56a996e3854599979fa35dab876109f533a + languageName: node + linkType: hard + "@opentelemetry/sdk-node@npm:^0.54.0": version: 0.54.2 resolution: "@opentelemetry/sdk-node@npm:0.54.2" @@ -14179,6 +14979,32 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/sdk-node@npm:^0.56.0": + version: 0.56.0 + resolution: "@opentelemetry/sdk-node@npm:0.56.0" + dependencies: + "@opentelemetry/api-logs": 0.56.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/exporter-logs-otlp-grpc": 0.56.0 + "@opentelemetry/exporter-logs-otlp-http": 0.56.0 + "@opentelemetry/exporter-logs-otlp-proto": 0.56.0 + "@opentelemetry/exporter-trace-otlp-grpc": 0.56.0 + "@opentelemetry/exporter-trace-otlp-http": 0.56.0 + "@opentelemetry/exporter-trace-otlp-proto": 0.56.0 + "@opentelemetry/exporter-zipkin": 1.29.0 + "@opentelemetry/instrumentation": 0.56.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/sdk-logs": 0.56.0 + "@opentelemetry/sdk-metrics": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + "@opentelemetry/sdk-trace-node": 1.29.0 + "@opentelemetry/semantic-conventions": 1.28.0 + peerDependencies: + "@opentelemetry/api": ">=1.3.0 <1.10.0" + checksum: f3261c1bf8a43f4a45bdc08fc80abf2abc9e0f59fbe557f7b6109078cfbd4bebfdd7c4289a907d02d0d2ef944efb72647718a68a3feb6c9676345ffbfe4e90bb + languageName: node + linkType: hard + "@opentelemetry/sdk-trace-base@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/sdk-trace-base@npm:1.27.0" @@ -14192,6 +15018,19 @@ __metadata: languageName: node linkType: hard +"@opentelemetry/sdk-trace-base@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/sdk-trace-base@npm:1.29.0" + dependencies: + "@opentelemetry/core": 1.29.0 + "@opentelemetry/resources": 1.29.0 + "@opentelemetry/semantic-conventions": 1.28.0 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: 750aa58f5323bda8391213d5bdabadbf2dfb28462198b87f7f41586fa7825cccfd04bdb1c199d3fd368f9837ba7d5f890cae1f7f5d29ec2aeb9e2b7f6a88ba37 + languageName: node + linkType: hard + "@opentelemetry/sdk-trace-node@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/sdk-trace-node@npm:1.27.0" @@ -14208,13 +15047,36 @@ __metadata: languageName: node linkType: hard -"@opentelemetry/semantic-conventions@npm:1.27.0, @opentelemetry/semantic-conventions@npm:^1.27.0": +"@opentelemetry/sdk-trace-node@npm:1.29.0": + version: 1.29.0 + resolution: "@opentelemetry/sdk-trace-node@npm:1.29.0" + dependencies: + "@opentelemetry/context-async-hooks": 1.29.0 + "@opentelemetry/core": 1.29.0 + "@opentelemetry/propagator-b3": 1.29.0 + "@opentelemetry/propagator-jaeger": 1.29.0 + "@opentelemetry/sdk-trace-base": 1.29.0 + semver: ^7.5.2 + peerDependencies: + "@opentelemetry/api": ">=1.0.0 <1.10.0" + checksum: f55a0ca916482d97227529783aa8506ab569a8835c0d39baadf93451e06b5eb44dbe8399be78ff080a89b24ab9a582d0fc1c5163bba641cbc4383a0f3da5f8b3 + languageName: node + linkType: hard + +"@opentelemetry/semantic-conventions@npm:1.27.0": version: 1.27.0 resolution: "@opentelemetry/semantic-conventions@npm:1.27.0" checksum: 26d85f8d13c8c64024f7a84528cff41d56afc9829e7ff8a654576404f8b2c1a9c264adcc6fa5a9551bacdd938a4a464041fa9493e0a722e5605f2c2ae6752398 languageName: node linkType: hard +"@opentelemetry/semantic-conventions@npm:1.28.0, @opentelemetry/semantic-conventions@npm:^1.27.0": + version: 1.28.0 + resolution: "@opentelemetry/semantic-conventions@npm:1.28.0" + checksum: 1d708afa654990236cdb6b5da84f7ab899b70bff9f753bc49d93616a5c7f7f339ba1eba6a9fbb57dee596995334f4e7effa57a4624741882ab5b3c419c3511e2 + languageName: node + linkType: hard + "@opentelemetry/sql-common@npm:^0.40.1": version: 0.40.1 resolution: "@opentelemetry/sql-common@npm:0.40.1" @@ -14226,14 +15088,16 @@ __metadata: languageName: node linkType: hard -"@oriflame/backstage-plugin-score-card@npm:^0.8.0": - version: 0.8.0 - resolution: "@oriflame/backstage-plugin-score-card@npm:0.8.0" +"@oriflame/backstage-plugin-score-card@npm:^0.9.0": + version: 0.9.1 + resolution: "@oriflame/backstage-plugin-score-card@npm:0.9.1" dependencies: "@backstage/catalog-model": ^1.4.3 "@backstage/config": ^1.1.1 "@backstage/core-components": ^0.13.10 "@backstage/core-plugin-api": ^1.8.2 + "@backstage/integration": ^1.9.0 + "@backstage/integration-react": ^1.1.24 "@backstage/plugin-catalog-common": ^1.0.20 "@backstage/plugin-catalog-react": ^1.9.3 "@backstage/theme": ^0.5.0 @@ -14242,13 +15106,13 @@ __metadata: "@material-ui/core": ^4.12.2 "@material-ui/icons": ^4.11.2 "@material-ui/lab": ^4.0.0-alpha.57 - "@types/react": ^18.0.0 + "@types/react": ^16.13.1 || ^17.0.0 || ^18.0.0 react-use: ^17.2.4 peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 - react-router-dom: ^6.4.3 - checksum: 4d1bf78b3fc6cce80b3cbc1abef5613bb609d2262e0d410aa57cc7e175eaf5cb727796ab61b44507f5c826b1f059f4ec03c280ce6cdbf7291d4461d745a9b5b6 + react: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 + react-router-dom: 6.0.0-beta.0 || ^6.3.0 + checksum: cebd9fd9f7d31e1b96765a02eefa2c817e401654bc28a40fe40236e0d79589760188e460797dbaf23ab56478120a60604403339267fb9ae9a9d23fcdfdb674a1 languageName: node linkType: hard @@ -14260,13 +15124,13 @@ __metadata: linkType: hard "@playwright/test@npm:^1.32.3": - version: 1.48.2 - resolution: "@playwright/test@npm:1.48.2" + version: 1.49.1 + resolution: "@playwright/test@npm:1.49.1" dependencies: - playwright: 1.48.2 + playwright: 1.49.1 bin: playwright: cli.js - checksum: 926e9411c800bbbf188271fe399f93d2abb1e50aac7844a44a698b3c6dae6f874a3715b1bf6d2f367dd53adb87d9f5d80d03ef71060901a59b6e227d8ed23826 + checksum: cdbd16df3d773dc8e522d79b4b961e25c2e1b1d4f3ec45eb711078ab5d11bca47caafe833e2be2f923328fbd012405a9ee31d9b449d184077598546a36847e69 languageName: node linkType: hard @@ -14984,6 +15848,62 @@ __metadata: languageName: node linkType: hard +"@redis/bloom@npm:1.2.0": + version: 1.2.0 + resolution: "@redis/bloom@npm:1.2.0" + peerDependencies: + "@redis/client": ^1.0.0 + checksum: 8c214227287d6b278109098bca00afc601cf84f7da9c6c24f4fa7d3854b946170e5893aa86ed607ba017a4198231d570541c79931b98b6d50b262971022d1d6c + languageName: node + linkType: hard + +"@redis/client@npm:1.6.0": + version: 1.6.0 + resolution: "@redis/client@npm:1.6.0" + dependencies: + cluster-key-slot: 1.1.2 + generic-pool: 3.9.0 + yallist: 4.0.0 + checksum: c01c89a793541dc6908a97f375fec3ac28bed7f92b1c20351a3073ce75c0263998a30c3316cbb76e6a4403059d9982d40aec0bc8f1b3cab43615edaaf05980da + 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: caf9b9a3ff82a08ae543c356a3fed548399ae79aba5ed08ce6cf1b522b955eb5cee4406b0ed0c6899345f8fbc06dfd6cd51304ae8422c3ebbc468f53294dc509 + 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: a84d51c06a2af9a42eff5a6db795e7c0f7ada27d958f5d762b6f9778f413399dbe6a0c2ab00dd7ccc5fdab5f2940afbab4a56c2b1c284a2326d0f79965d5bba1 + 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: 256ddf8b30f216b605e571c9085e0efd5e3b43229b57db8ba0eea3376540ada437b68509c3bb0354e3c784f5fa1b825593cc602ebbfc5cbfa9e46d5c7be67eb6 + 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: 785f024e1c83866708beb254f765e561ccd6e6caad61b697223b3355ee92ca1e99a4d312c4ce03a3d6a29a223f38a2ec844c80b47990fa3bd9ddc56a30c1376f + languageName: node + linkType: hard + "@remix-run/router@npm:1.21.0": version: 1.21.0 resolution: "@remix-run/router@npm:1.21.0" @@ -14998,6 +15918,15 @@ __metadata: languageName: node linkType: hard +"@remixicon/react@npm:^4.5.0": + version: 4.5.0 + resolution: "@remixicon/react@npm:4.5.0" + peerDependencies: + react: ">=18.2.0" + checksum: e37b61090954954601d35367a740b7be30c105a49f67eaa5a697db16d4668d71d9fd94b339da6d449a254736d5af3b567d3694021b79d3c82fe28afb818830bc + languageName: node + linkType: hard + "@repeaterjs/repeater@npm:^3.0.4": version: 3.0.5 resolution: "@repeaterjs/repeater@npm:3.0.5" @@ -15005,9 +15934,9 @@ __metadata: languageName: node linkType: hard -"@rjsf/core@npm:5.21.2": - version: 5.21.2 - resolution: "@rjsf/core@npm:5.21.2" +"@rjsf/core@npm:5.23.1": + version: 5.23.1 + resolution: "@rjsf/core@npm:5.23.1" dependencies: lodash: ^4.17.21 lodash-es: ^4.17.21 @@ -15015,28 +15944,28 @@ __metadata: nanoid: ^3.3.7 prop-types: ^15.8.1 peerDependencies: - "@rjsf/utils": ^5.20.x + "@rjsf/utils": ^5.23.x react: ^16.14.0 || >=17 - checksum: ac5c4ff0e0cf74ba8cf6d58df314f8f17de6be5b00bb0ca14f79861347bbaa59f37b8f572d80f30388c5007de1d2dedfc3ff70e419eb874331d58f0ba9eeeb42 + checksum: acb5b1541b7e6f9911dce33455c297402fc1b2278b0c688073decdea977efae7d4227962eaadeb48fd14c2a8e4bba73a80df975b1c49aa2e2b933c2646ab4904 languageName: node linkType: hard -"@rjsf/material-ui@npm:5.21.2": - version: 5.21.2 - resolution: "@rjsf/material-ui@npm:5.21.2" +"@rjsf/material-ui@npm:5.23.1": + version: 5.23.1 + resolution: "@rjsf/material-ui@npm:5.23.1" peerDependencies: "@material-ui/core": ^4.12.3 "@material-ui/icons": ^4.11.2 - "@rjsf/core": ^5.20.x - "@rjsf/utils": ^5.20.x + "@rjsf/core": ^5.23.x + "@rjsf/utils": ^5.23.x react: ^16.14.0 || >=17 - checksum: 868d86f0a9786b0404734628d5fd158ab1bed4bb6eed8b23cdcdb3e68c398993b6ea8edb5ff4cc68006b081bfeaecb2e5ee6252872604d2124e9dc3078732676 + checksum: ae0d401edd407c534406cce60fda2725fc246286cbedd8a8e4031097d4d318761fd8a4f35339d0f3f857a3dc863b88a75002d6900176052913bb629d0ebde4f9 languageName: node linkType: hard -"@rjsf/utils@npm:5.21.2": - version: 5.21.2 - resolution: "@rjsf/utils@npm:5.21.2" +"@rjsf/utils@npm:5.23.1": + version: 5.23.1 + resolution: "@rjsf/utils@npm:5.23.1" dependencies: json-schema-merge-allof: ^0.8.1 jsonpointer: ^5.0.1 @@ -15045,21 +15974,21 @@ __metadata: react-is: ^18.2.0 peerDependencies: react: ^16.14.0 || >=17 - checksum: 05460f3c95e1a407001accaf2e9b90c0731433936cfea6a129ac01b49575f56ba336f1ae46e3930f0226580d06c6300c8622d1c3a56354c3e723caf3654f02e1 + checksum: 7580419cf07416fe1e608ed171c30b25b3a78cfebba7d97e3120fe2e40f702fd0e61494e6c823281091522b053a39a83ab31ceb97c078cfb39ac636dc2d997c1 languageName: node linkType: hard -"@rjsf/validator-ajv8@npm:5.21.2": - version: 5.21.2 - resolution: "@rjsf/validator-ajv8@npm:5.21.2" +"@rjsf/validator-ajv8@npm:5.23.1": + version: 5.23.1 + resolution: "@rjsf/validator-ajv8@npm:5.23.1" dependencies: ajv: ^8.12.0 ajv-formats: ^2.1.1 lodash: ^4.17.21 lodash-es: ^4.17.21 peerDependencies: - "@rjsf/utils": ^5.20.x - checksum: 06d34e70e6595c5a0e999a3a2a651fccc7a36dbb2395f5805ce1ac6b47201111e6d84c9e122f3d336bbdbaca61875a90efd65e1839d9da3c9aafe282dcc03086 + "@rjsf/utils": ^5.23.x + checksum: 3eca428bd682ea8226558e0c719f263912ad8d6fde2c3ee817c5c106070fd3142f614dc35e15819000f8f00f9c00aa654c2dab5fd3a7318164ad6420d53068f5 languageName: node linkType: hard @@ -15172,208 +16101,208 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.27.2" +"@rollup/rollup-android-arm-eabi@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.27.4" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-android-arm64@npm:4.27.2" +"@rollup/rollup-android-arm64@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-android-arm64@npm:4.27.4" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-darwin-arm64@npm:4.27.2" +"@rollup/rollup-darwin-arm64@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-darwin-arm64@npm:4.27.4" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-darwin-x64@npm:4.27.2" +"@rollup/rollup-darwin-x64@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-darwin-x64@npm:4.27.4" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.27.2" +"@rollup/rollup-freebsd-arm64@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.27.4" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-freebsd-x64@npm:4.27.2" +"@rollup/rollup-freebsd-x64@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-freebsd-x64@npm:4.27.4" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.27.2" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.27.4" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.27.2" +"@rollup/rollup-linux-arm-musleabihf@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.27.4" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.27.2" +"@rollup/rollup-linux-arm64-gnu@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.27.4" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.27.2" +"@rollup/rollup-linux-arm64-musl@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.27.4" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.2" +"@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.27.4" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.27.2" +"@rollup/rollup-linux-riscv64-gnu@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.27.4" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.27.2" +"@rollup/rollup-linux-s390x-gnu@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.27.4" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.27.2" +"@rollup/rollup-linux-x64-gnu@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.27.4" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.27.2" +"@rollup/rollup-linux-x64-musl@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.27.4" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.27.2" +"@rollup/rollup-win32-arm64-msvc@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.27.4" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.27.2" +"@rollup/rollup-win32-ia32-msvc@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.27.4" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.27.2": - version: 4.27.2 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.27.2" +"@rollup/rollup-win32-x64-msvc@npm:4.27.4": + version: 4.27.4 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.27.4" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rspack/binding-darwin-arm64@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-darwin-arm64@npm:1.1.1" +"@rspack/binding-darwin-arm64@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-darwin-arm64@npm:1.1.5" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-darwin-x64@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-darwin-x64@npm:1.1.1" +"@rspack/binding-darwin-x64@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-darwin-x64@npm:1.1.5" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rspack/binding-linux-arm64-gnu@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-linux-arm64-gnu@npm:1.1.1" +"@rspack/binding-linux-arm64-gnu@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-linux-arm64-gnu@npm:1.1.5" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-arm64-musl@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-linux-arm64-musl@npm:1.1.1" +"@rspack/binding-linux-arm64-musl@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-linux-arm64-musl@npm:1.1.5" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rspack/binding-linux-x64-gnu@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-linux-x64-gnu@npm:1.1.1" +"@rspack/binding-linux-x64-gnu@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-linux-x64-gnu@npm:1.1.5" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rspack/binding-linux-x64-musl@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-linux-x64-musl@npm:1.1.1" +"@rspack/binding-linux-x64-musl@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-linux-x64-musl@npm:1.1.5" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rspack/binding-win32-arm64-msvc@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-win32-arm64-msvc@npm:1.1.1" +"@rspack/binding-win32-arm64-msvc@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-win32-arm64-msvc@npm:1.1.5" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rspack/binding-win32-ia32-msvc@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-win32-ia32-msvc@npm:1.1.1" +"@rspack/binding-win32-ia32-msvc@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-win32-ia32-msvc@npm:1.1.5" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rspack/binding-win32-x64-msvc@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding-win32-x64-msvc@npm:1.1.1" +"@rspack/binding-win32-x64-msvc@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding-win32-x64-msvc@npm:1.1.5" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rspack/binding@npm:1.1.1": - version: 1.1.1 - resolution: "@rspack/binding@npm:1.1.1" +"@rspack/binding@npm:1.1.5": + version: 1.1.5 + resolution: "@rspack/binding@npm:1.1.5" dependencies: - "@rspack/binding-darwin-arm64": 1.1.1 - "@rspack/binding-darwin-x64": 1.1.1 - "@rspack/binding-linux-arm64-gnu": 1.1.1 - "@rspack/binding-linux-arm64-musl": 1.1.1 - "@rspack/binding-linux-x64-gnu": 1.1.1 - "@rspack/binding-linux-x64-musl": 1.1.1 - "@rspack/binding-win32-arm64-msvc": 1.1.1 - "@rspack/binding-win32-ia32-msvc": 1.1.1 - "@rspack/binding-win32-x64-msvc": 1.1.1 + "@rspack/binding-darwin-arm64": 1.1.5 + "@rspack/binding-darwin-x64": 1.1.5 + "@rspack/binding-linux-arm64-gnu": 1.1.5 + "@rspack/binding-linux-arm64-musl": 1.1.5 + "@rspack/binding-linux-x64-gnu": 1.1.5 + "@rspack/binding-linux-x64-musl": 1.1.5 + "@rspack/binding-win32-arm64-msvc": 1.1.5 + "@rspack/binding-win32-ia32-msvc": 1.1.5 + "@rspack/binding-win32-x64-msvc": 1.1.5 dependenciesMeta: "@rspack/binding-darwin-arm64": optional: true @@ -15393,16 +16322,16 @@ __metadata: optional: true "@rspack/binding-win32-x64-msvc": optional: true - checksum: 3e5de458aef597426a31cc84328d876959b4b873fed260d84881b1b08f3035d221a7d25a0ad00512058de0c63f43611698d90147677fb85b10aaa4ac6e063cea + checksum: 6fe7d4cd04613c8c25d1e5eabf97abd82c721ec68f787150eab3026ef01830043e9c062851a286618106cadca759fc55929ec39b85b12e21025cffd39655dfc6 languageName: node linkType: hard "@rspack/core@npm:^1.0.10": - version: 1.1.1 - resolution: "@rspack/core@npm:1.1.1" + version: 1.1.5 + resolution: "@rspack/core@npm:1.1.5" dependencies: "@module-federation/runtime-tools": 0.5.1 - "@rspack/binding": 1.1.1 + "@rspack/binding": 1.1.5 "@rspack/lite-tapable": 1.0.1 caniuse-lite: ^1.0.30001616 peerDependencies: @@ -15410,13 +16339,13 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 6e750ebc6876c203e716e227cec26a91f0d83ba24dffaae86627455dfec9375b5661220cbead6c97e59a3f54f24659f311a03373d62b3f0005c38351e664d310 + checksum: 795da019b01555f7f3035ee1c80f39d808ddd1a6043aa2ab8caa3c42e3f73f966fb581bcb9c959852fd31d52ea8f89e2a135c8fa29c31cb7effa7d237a854520 languageName: node linkType: hard "@rspack/dev-server@npm:^1.0.9": - version: 1.0.9 - resolution: "@rspack/dev-server@npm:1.0.9" + version: 1.0.10 + resolution: "@rspack/dev-server@npm:1.0.10" dependencies: chokidar: ^3.6.0 connect-history-api-fallback: ^2.0.0 @@ -15429,7 +16358,7 @@ __metadata: ws: ^8.16.0 peerDependencies: "@rspack/core": "*" - checksum: 46b6ad1e8f52a44c178042b6b9306fe54ad28ab24b86015f118d03a69628b04bf9563201686e0738b8c06ee8c5dedbc0bb4d6705c7f2d7d3959f2a449ff95cd6 + checksum: 0df53d1a655e5eb95c3a84b8ef34bcab6d32f8c7b23ba080f9691aa15edeee6dd79236c3942c1d55834ff9ae9f427b6e5f58cbf5e10aae015979f3d171bd65ef languageName: node linkType: hard @@ -15441,17 +16370,17 @@ __metadata: linkType: hard "@rspack/plugin-react-refresh@npm:^1.0.0": - version: 1.0.0 - resolution: "@rspack/plugin-react-refresh@npm:1.0.0" + version: 1.0.1 + resolution: "@rspack/plugin-react-refresh@npm:1.0.1" dependencies: - error-stack-parser: ^2.0.6 - html-entities: ^2.1.0 + error-stack-parser: ^2.1.4 + html-entities: ^2.5.2 peerDependencies: react-refresh: ">=0.10.0 <1.0.0" peerDependenciesMeta: react-refresh: optional: true - checksum: 88212e66da7e51d99228c7d77b683ef020ba2f70ea7ed546158167eaa4d6e3fa228da2f7d660c3f7a74ad69a47bc98c67a2d11e4a403f3e1ff8523cded67c6c0 + checksum: 876e75b28cbafa0b405cc68768cb9fd4e394531e5c8e1515dc20fb4bd72e1bef23cb055475fc286f5d215f16ab38e4c571731c38398a85e5066b8fbee86449b0 languageName: node linkType: hard @@ -15544,6 +16473,13 @@ __metadata: languageName: node linkType: hard +"@sec-ant/readable-stream@npm:^0.4.1": + version: 0.4.1 + resolution: "@sec-ant/readable-stream@npm:0.4.1" + checksum: eb56f72a70995f725269f1c1c206d6dbeb090e88413b1302a456c600041175a7a484c2f0172454f7bed65a8ab95ffed7647d8ad03e6c23b1e3bbc9845f78cd17 + languageName: node + linkType: hard + "@segment/analytics-core@npm:1.4.1": version: 1.4.1 resolution: "@segment/analytics-core@npm:1.4.1" @@ -15750,13 +16686,13 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^3.1.2, @smithy/abort-controller@npm:^3.1.6": - version: 3.1.6 - resolution: "@smithy/abort-controller@npm:3.1.6" +"@smithy/abort-controller@npm:^3.1.2, @smithy/abort-controller@npm:^3.1.8": + version: 3.1.8 + resolution: "@smithy/abort-controller@npm:3.1.8" dependencies: - "@smithy/types": ^3.6.0 + "@smithy/types": ^3.7.1 tslib: ^2.6.2 - checksum: abba34cc47b6f7951402da1f94465616b84dedf55e0b0467b53f7848b9cb3e82b94869fa637278aa2f65809613e872582791053fd23299e026edada4a5ec1c1c + checksum: edfe448be34e33120dfb11a564e87362288ed76d69eaae3449d5f1ee806def1fc844c35421caf2cf579e3bc45df97340e74e36927ec439c8c8aca5c5edf8fb85 languageName: node linkType: hard @@ -16041,15 +16977,15 @@ __metadata: linkType: hard "@smithy/node-http-handler@npm:^3.0.0, @smithy/node-http-handler@npm:^3.2.0": - version: 3.2.5 - resolution: "@smithy/node-http-handler@npm:3.2.5" + version: 3.3.1 + resolution: "@smithy/node-http-handler@npm:3.3.1" dependencies: - "@smithy/abort-controller": ^3.1.6 - "@smithy/protocol-http": ^4.1.5 - "@smithy/querystring-builder": ^3.0.8 - "@smithy/types": ^3.6.0 + "@smithy/abort-controller": ^3.1.8 + "@smithy/protocol-http": ^4.1.7 + "@smithy/querystring-builder": ^3.0.10 + "@smithy/types": ^3.7.1 tslib: ^2.6.2 - checksum: ea8d4148dd760f031f9eeb2aec2480685bb1a40d7ac9c482eb3170df0316cae58433a6c803d85b046c132a19b8b4874741fae054355b5584facbd46c18889c83 + checksum: 483766a6f7d9625b254a1e88f54c0bd89e83bb0c3a3518d3b298dcd9bbc2160bca2e867a859654c483aed78e8578e0c3c65ae4e0c4aa6e5e50bc04cdb7af1b37 languageName: node linkType: hard @@ -16063,24 +16999,24 @@ __metadata: languageName: node linkType: hard -"@smithy/protocol-http@npm:^4.1.1, @smithy/protocol-http@npm:^4.1.5": - version: 4.1.5 - resolution: "@smithy/protocol-http@npm:4.1.5" +"@smithy/protocol-http@npm:^4.1.1, @smithy/protocol-http@npm:^4.1.7": + version: 4.1.7 + resolution: "@smithy/protocol-http@npm:4.1.7" dependencies: - "@smithy/types": ^3.6.0 + "@smithy/types": ^3.7.1 tslib: ^2.6.2 - checksum: 2e581594d03ff367ebc0a1ab0443e8b148f39a3ea810333861f4aed639239e5a261bedbb49f6555cfdb9682b88cd881715764c2dfe7e18a7a003385a0b6200d5 + checksum: 3d78a52558edb712e7b399535fcb9de5960610dc4b81ce15f1b52c7ac3ea96f47c53132974ce9e1108378dc1c5ee90333828dfa1a071dff7b49cf7b687537452 languageName: node linkType: hard -"@smithy/querystring-builder@npm:^3.0.4, @smithy/querystring-builder@npm:^3.0.8": - version: 3.0.8 - resolution: "@smithy/querystring-builder@npm:3.0.8" +"@smithy/querystring-builder@npm:^3.0.10, @smithy/querystring-builder@npm:^3.0.4": + version: 3.0.10 + resolution: "@smithy/querystring-builder@npm:3.0.10" dependencies: - "@smithy/types": ^3.6.0 + "@smithy/types": ^3.7.1 "@smithy/util-uri-escape": ^3.0.0 tslib: ^2.6.2 - checksum: b07a766fb1e94e06116aef6534a31bbd4bb1bb94844d61c67615316d19aac82f94781fab779655bc03a46d70dda9caf3ad991a3e41548fbbba92783103f4f43e + checksum: a789b6f43392247880d71a4d88a89309d2da0c66e2c0f1708c9befd19db66151b8653e6ba3a13cb9aae2a9ed3889245ad394ecdb1076c25b447296b0a4d83877 languageName: node linkType: hard @@ -16152,12 +17088,12 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^3.4.0, @smithy/types@npm:^3.6.0": - version: 3.6.0 - resolution: "@smithy/types@npm:3.6.0" +"@smithy/types@npm:^3.4.0, @smithy/types@npm:^3.7.1": + version: 3.7.1 + resolution: "@smithy/types@npm:3.7.1" dependencies: tslib: ^2.6.2 - checksum: 4f581dc1c3e2dee8e1134fafb47de2c301330ea668214eb1a81d26b85acdb48a7e52008da0d15a402e998a79bed285a74b88949a5a4a3fe0aef38c28620ab795 + checksum: 8db4393211db97aec515cc06748fa23acfc0c26a19c5ed6d009add623e1b1b7a470603a71f55b9de31a15696a2918e4a0913cb3531bfc7951b80bc7872f594f0 languageName: node linkType: hard @@ -16410,15 +17346,6 @@ __metadata: languageName: node linkType: hard -"@spotify/prettier-config@npm:^15.0.0": - version: 15.0.0 - resolution: "@spotify/prettier-config@npm:15.0.0" - peerDependencies: - prettier: 2.x - checksum: aa5ec5739427f9acdb9d62ae6c04f04a344898567239f7ee45c75c6205ebdffbc61747ea8de6e83baf0bc3785359967de4b7097a8723c4b4063ff57dc5cb6c44 - languageName: node - linkType: hard - "@stoplight/better-ajv-errors@npm:1.0.3": version: 1.0.3 resolution: "@stoplight/better-ajv-errors@npm:1.0.3" @@ -16501,9 +17428,9 @@ __metadata: languageName: node linkType: hard -"@stoplight/spectral-core@npm:^1.18.0, @stoplight/spectral-core@npm:^1.18.3, @stoplight/spectral-core@npm:^1.19.2, @stoplight/spectral-core@npm:^1.8.1": - version: 1.19.3 - resolution: "@stoplight/spectral-core@npm:1.19.3" +"@stoplight/spectral-core@npm:^1.18.0, @stoplight/spectral-core@npm:^1.18.3, @stoplight/spectral-core@npm:^1.19.2, @stoplight/spectral-core@npm:^1.19.4, @stoplight/spectral-core@npm:^1.8.1": + version: 1.19.4 + resolution: "@stoplight/spectral-core@npm:1.19.4" dependencies: "@stoplight/better-ajv-errors": 1.0.3 "@stoplight/json": ~3.21.0 @@ -16518,7 +17445,7 @@ __metadata: ajv-errors: ~3.0.0 ajv-formats: ~2.1.0 es-aggregate-error: ^1.0.7 - jsonpath-plus: 10.1.0 + jsonpath-plus: 10.2.0 lodash: ~4.17.21 lodash.topath: ^4.5.2 minimatch: 3.1.2 @@ -16526,7 +17453,7 @@ __metadata: pony-cause: ^1.1.1 simple-eval: 1.0.1 tslib: ^2.8.1 - checksum: 7e04c72d3d72dc774b35e3fbbbcf104a1c0c4f1823c195fcf12fe86ce038d2e5e80089b843e6af5ff79a43ebf9807eb3035468847a5b6911fd4f5429a232799a + checksum: c9efb0892a80f66f58309e297e7cb27580847403a5625f95b0332dbba4e3fe360f04aa60339d61824a025e3ee6296c2f73e1ca7119b783f9349f21d971b73dd8 languageName: node linkType: hard @@ -16543,11 +17470,11 @@ __metadata: linkType: hard "@stoplight/spectral-formatters@npm:^1.1.0": - version: 1.4.2 - resolution: "@stoplight/spectral-formatters@npm:1.4.2" + version: 1.4.3 + resolution: "@stoplight/spectral-formatters@npm:1.4.3" dependencies: "@stoplight/path": ^1.3.2 - "@stoplight/spectral-core": ^1.19.2 + "@stoplight/spectral-core": ^1.19.4 "@stoplight/spectral-runtime": ^1.1.2 "@stoplight/types": ^13.15.0 "@types/markdown-escape": ^1.1.3 @@ -16559,17 +17486,17 @@ __metadata: strip-ansi: 6.0 text-table: ^0.2.0 tslib: ^2.8.1 - checksum: 5d07007d4155f445ac9a336a914bb3e10b43eb6a7f05ef1e32cb81d4b9e54d570d0e5febb76f7cca2a8a0b879e62d3cbc8e96f31ef50c3f572b63d3ad77f6ad6 + checksum: 949d82f1a790136357a305a71cb96cfd77ad4bff044941e36eecb98b30601aec92b6020d1869f5eca54e03c0c7e6e5aeb74346327489973332192629fbafdff7 languageName: node linkType: hard "@stoplight/spectral-functions@npm:^1.6.1, @stoplight/spectral-functions@npm:^1.7.2, @stoplight/spectral-functions@npm:^1.9.1": - version: 1.9.2 - resolution: "@stoplight/spectral-functions@npm:1.9.2" + version: 1.9.3 + resolution: "@stoplight/spectral-functions@npm:1.9.3" dependencies: "@stoplight/better-ajv-errors": 1.0.3 "@stoplight/json": ^3.17.1 - "@stoplight/spectral-core": ^1.19.2 + "@stoplight/spectral-core": ^1.19.4 "@stoplight/spectral-formats": ^1.8.1 "@stoplight/spectral-runtime": ^1.1.2 ajv: ^8.17.1 @@ -16578,7 +17505,7 @@ __metadata: ajv-formats: ~2.1.0 lodash: ~4.17.21 tslib: ^2.8.1 - checksum: 98c4b2f7db280a82bb2a3cb310c4a335482e77c635277fe620f440fbb2e7aaede22ad3e2c30cfd9acf7da8f9dd6acdd90e66d378f88c8b95a5eee5d1725ee879 + checksum: bdb1c95b12b4ebef4f429621dd9f1b30134b07c23086573ad1e937cfc7b15d60c52cb2810939e030a8f8edb59100d198a40ee1278b832869ca71b058a0e857b1 languageName: node linkType: hard @@ -16608,13 +17535,13 @@ __metadata: linkType: hard "@stoplight/spectral-rulesets@npm:^1.14.1, @stoplight/spectral-rulesets@npm:^1.18.0": - version: 1.21.2 - resolution: "@stoplight/spectral-rulesets@npm:1.21.2" + version: 1.21.3 + resolution: "@stoplight/spectral-rulesets@npm:1.21.3" dependencies: "@asyncapi/specs": ^6.8.0 "@stoplight/better-ajv-errors": 1.0.3 "@stoplight/json": ^3.17.0 - "@stoplight/spectral-core": ^1.19.2 + "@stoplight/spectral-core": ^1.19.4 "@stoplight/spectral-formats": ^1.8.1 "@stoplight/spectral-functions": ^1.9.1 "@stoplight/spectral-runtime": ^1.1.2 @@ -16626,7 +17553,7 @@ __metadata: leven: 3.1.0 lodash: ~4.17.21 tslib: ^2.8.1 - checksum: ec63bc8955426828a4aaf9e5f05a05ce5f2ed574dc747b5e5fc35acbf7bdf4b326ae2df47f2e240e39e5010f77ac2272cb5027427b4d44b5c6f33f4d4c41d7a1 + checksum: 41aa70864efb46074b24f63101eeb472644dea703b9ac55640ca9e398e2e4f8e9de3c46fe502b9912c2629441113e51d80d9a171689b5122ff40bb13072dc43b languageName: node linkType: hard @@ -16694,6 +17621,493 @@ __metadata: languageName: node linkType: hard +"@storybook/addon-actions@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-actions@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + "@types/uuid": ^9.0.1 + dequal: ^2.0.2 + polished: ^4.2.2 + uuid: ^9.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 93a453321f14eddf7f58e4c235e6ebbee5a9b680453834cc5593ff59d7607d9e99c53d5fac9bf59f6072c3a6f64a5f53174078c9e6c9054b125dc4c25be43842 + languageName: node + linkType: hard + +"@storybook/addon-backgrounds@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-backgrounds@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + memoizerific: ^1.11.3 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: acedc2b2b74dafc6cd236ec815f568b33f9cbf2eb714209f3ef8594df9bff29b72cf3d3aba3e778cb0cd962acaa7352657de353914353fbbd235d0ff37acfbd2 + languageName: node + linkType: hard + +"@storybook/addon-controls@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-controls@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + dequal: ^2.0.2 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: bd0804d54d7dbcf4a557738240aaf07c4cc1f022141c85f13d62a0029d8d363b1a7435330f0ee161cc3519e597a0bcfe4f7c16285447cca4eda23148d6a1cb4c + languageName: node + linkType: hard + +"@storybook/addon-docs@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-docs@npm:8.4.6" + dependencies: + "@mdx-js/react": ^3.0.0 + "@storybook/blocks": 8.4.6 + "@storybook/csf-plugin": 8.4.6 + "@storybook/react-dom-shim": 8.4.6 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 767bdbc9c83ac10129ec5863ccf2b658ad1807e1a22def2f734d4edde1791291d66186eca30a31ce57cf1863601a03dde075441ef60a9b0e66080a16ca9ed481 + languageName: node + linkType: hard + +"@storybook/addon-essentials@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-essentials@npm:8.4.6" + dependencies: + "@storybook/addon-actions": 8.4.6 + "@storybook/addon-backgrounds": 8.4.6 + "@storybook/addon-controls": 8.4.6 + "@storybook/addon-docs": 8.4.6 + "@storybook/addon-highlight": 8.4.6 + "@storybook/addon-measure": 8.4.6 + "@storybook/addon-outline": 8.4.6 + "@storybook/addon-toolbars": 8.4.6 + "@storybook/addon-viewport": 8.4.6 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 72915e83a3cbae4c302d76721f1b3446455f7dbc49f76234e8b25f673cf69f448a1c3aeae121e800bec4aee35c55031ef1b430a0827e358c6dce4ee17375704a + languageName: node + linkType: hard + +"@storybook/addon-highlight@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-highlight@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 6549a3e859f3ed20a7defe73fa91eda0753d6412210a1c0fdcbc51c48f55a963064743224b56285b4c9d7d42a8fc195cbd5c052ac992c34fbcec798de9368e98 + languageName: node + linkType: hard + +"@storybook/addon-interactions@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-interactions@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + "@storybook/instrumenter": 8.4.6 + "@storybook/test": 8.4.6 + polished: ^4.2.2 + ts-dedent: ^2.2.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 7ab3e92943b4073c54546a4fb6e1760524f8af60b3acd18ddac57b164094984f3331b76b9b35ee5d05c820bcf34d6e254ad93346fbf352030641a7b599deff89 + languageName: node + linkType: hard + +"@storybook/addon-measure@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-measure@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + tiny-invariant: ^1.3.1 + peerDependencies: + storybook: ^8.4.6 + checksum: 30a73659f2eafea2cfcd4727c6af159739e33d8de6e7aa9703311d4de1c752f512a0cdbea76079a6169f5bcbdd0519771284d18d050374e3e4721d12d780fe9b + languageName: node + linkType: hard + +"@storybook/addon-outline@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-outline@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 82b864ecc476d1c8b2ff8ccb587868b7a81610f527706873fbe4846a31f865b5c8bc17c3f59991ba73b0c200ecd06b1a4d75c5903024f7763cd0a0d1efcba322 + languageName: node + linkType: hard + +"@storybook/addon-styling-webpack@npm:^1.0.1": + version: 1.0.1 + resolution: "@storybook/addon-styling-webpack@npm:1.0.1" + dependencies: + "@storybook/node-logger": ^8.0.0-alpha.10 + peerDependencies: + webpack: ^5.0.0 + checksum: 3a507f9e944d1b23f97c201a59169c62e5d3fe7a750226a1fd13a2941d96a92543b87b1bcda3deb780831505fa75956b1ebd1838a7445495831c9a63f9b192b9 + languageName: node + linkType: hard + +"@storybook/addon-themes@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-themes@npm:8.4.6" + dependencies: + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: 6f41a7c2de3158320e3af3ce134e1b4d0dd26ba34fd7545c02e87557348498fd815dfba4f350d5c98c078768e773d43bd1a84d06110e0d55dac7897e68d2d58f + languageName: node + linkType: hard + +"@storybook/addon-toolbars@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-toolbars@npm:8.4.6" + peerDependencies: + storybook: ^8.4.6 + checksum: 7b5737c2d1eb62ab8ce3245b3791ab0000b745aab9094beca52a146af335c4caf9df9429d9f868184e3ff05ba8952a5f2d5bc82f7a863a67fec24f22abf90d4d + languageName: node + linkType: hard + +"@storybook/addon-viewport@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/addon-viewport@npm:8.4.6" + dependencies: + memoizerific: ^1.11.3 + peerDependencies: + storybook: ^8.4.6 + checksum: ada45a76dc0311a7c8b8740ef6ca5f7f78201252d2157595a01c50f7de3773ebda4daf3a7ad0744687c8d6cbf730fc8c731b229029068ff6020eb09d9ed03e93 + languageName: node + linkType: hard + +"@storybook/addon-webpack5-compiler-swc@npm:^1.0.5": + version: 1.0.5 + resolution: "@storybook/addon-webpack5-compiler-swc@npm:1.0.5" + dependencies: + "@swc/core": ^1.7.3 + swc-loader: ^0.2.3 + checksum: ed3177427f528cb1842bc57c9bc32501140c9a5bdf14926959cba024d38e5d6a24bccb6c977666e3a0a58dc7890feb92c616ec1f43bed33e691cbb1c5a575bd0 + languageName: node + linkType: hard + +"@storybook/blocks@npm:8.4.6, @storybook/blocks@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/blocks@npm:8.4.6" + dependencies: + "@storybook/csf": ^0.1.11 + "@storybook/icons": ^1.2.12 + ts-dedent: ^2.0.0 + 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.4.6 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + checksum: 355c242c2dbc0ae11816b1882673db4e2c2ffe354284a023717d29ef23a623f1b0ff945798018293c20092c7a2d89d302f8ac48e6156deb90f313a426a9d1c74 + languageName: node + linkType: hard + +"@storybook/builder-webpack5@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/builder-webpack5@npm:8.4.6" + dependencies: + "@storybook/core-webpack": 8.4.6 + "@types/node": ^22.0.0 + "@types/semver": ^7.3.4 + browser-assert: ^1.2.1 + case-sensitive-paths-webpack-plugin: ^2.4.0 + cjs-module-lexer: ^1.2.3 + constants-browserify: ^1.0.0 + css-loader: ^6.7.1 + es-module-lexer: ^1.5.0 + fork-ts-checker-webpack-plugin: ^8.0.0 + html-webpack-plugin: ^5.5.0 + magic-string: ^0.30.5 + path-browserify: ^1.0.1 + process: ^0.11.10 + semver: ^7.3.7 + style-loader: ^3.3.1 + terser-webpack-plugin: ^5.3.1 + ts-dedent: ^2.0.0 + url: ^0.11.0 + util: ^0.12.4 + util-deprecate: ^1.0.2 + webpack: 5 + webpack-dev-middleware: ^6.1.2 + webpack-hot-middleware: ^2.25.1 + webpack-virtual-modules: ^0.6.0 + peerDependencies: + storybook: ^8.4.6 + peerDependenciesMeta: + typescript: + optional: true + checksum: 8a45e5089ff5d644426fe5131718d53aefc2c4d638cfaa07cef7bfcec325cac000932d18e732df7899bb89f100e401c32b6a06f0787fd290153d949087daf2d4 + languageName: node + linkType: hard + +"@storybook/components@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/components@npm:8.4.6" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 66b08f840017e279274a0be2d9cba9edaa50139d5d7cdd9f148ff815f693db0026531e3e15efc9706c9e32aeccb0a97717aca7b81a2119b79f5875a69f0b81a3 + languageName: node + linkType: hard + +"@storybook/core-webpack@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/core-webpack@npm:8.4.6" + dependencies: + "@types/node": ^22.0.0 + ts-dedent: ^2.0.0 + peerDependencies: + storybook: ^8.4.6 + checksum: d42870e9225d561618115631240728df16cc36e08a7a8e4b68701f28341a289cfb110b4333158e24ea975d18df30412d11808b5be407141db704dd932e59d531 + languageName: node + linkType: hard + +"@storybook/core@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/core@npm:8.4.6" + dependencies: + "@storybook/csf": ^0.1.11 + better-opn: ^3.0.2 + browser-assert: ^1.2.1 + esbuild: ^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 + esbuild-register: ^3.5.0 + jsdoc-type-pratt-parser: ^4.0.0 + process: ^0.11.10 + recast: ^0.23.5 + semver: ^7.6.2 + util: ^0.12.5 + ws: ^8.2.3 + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + checksum: c9c4b5aa1f49ee8e3b51c2e179cbafd6826415e6a788a0b11a04bf0dedbbb56b81dd187719086cdeb695fa31c46709dc6184027e2938eb5fc9ab41c4ed2b15d7 + languageName: node + linkType: hard + +"@storybook/csf-plugin@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/csf-plugin@npm:8.4.6" + dependencies: + unplugin: ^1.3.1 + peerDependencies: + storybook: ^8.4.6 + checksum: e09a2175bc3af950668a307626bcc68b51c88b8404e39f2a57942097ff638b5c997aafaaf694493dac611b11572863f8a9cb6246c0b117a07c0d650299fff620 + languageName: node + linkType: hard + +"@storybook/csf@npm:^0.1.11": + version: 0.1.11 + resolution: "@storybook/csf@npm:0.1.11" + dependencies: + type-fest: ^2.19.0 + checksum: ba2a265f62ad82a2853b069f77e974efe31bed263a640ca1dd8e6d7e194022018a67ad4a2587ae928f33ae45aaf6ffedd5925ba3fcf3fe5b7996667a918e22eb + languageName: node + linkType: hard + +"@storybook/global@npm:^5.0.0": + version: 5.0.0 + resolution: "@storybook/global@npm:5.0.0" + checksum: ede0ad35ec411fe31c61150dbd118fef344d1d0e72bf5d3502368e35cf68126f6b7ae4a0ab5e2ffe2f0baa3b4286f03ad069ba3e098e1725449ef08b7e154ba8 + languageName: node + linkType: hard + +"@storybook/icons@npm:^1.2.12": + version: 1.2.12 + resolution: "@storybook/icons@npm:1.2.12" + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + checksum: a4c87cbfadfa1369680c4acc9d5ef90b9ff23e2ad603b6c0aba0dafe89780e5643c567160eb0544fe33f3b9f157adda2621ae45b4036ac001139a34926e00102 + languageName: node + linkType: hard + +"@storybook/instrumenter@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/instrumenter@npm:8.4.6" + dependencies: + "@storybook/global": ^5.0.0 + "@vitest/utils": ^2.1.1 + peerDependencies: + storybook: ^8.4.6 + checksum: faa8e6ec52a4e8ef0313601e477cc1a8097960774f5d98bc2e928539dc785eaf5c7e0659fe8013f0c18c09222de92fb68667e728219d73d3b39b3bafe3bb815c + languageName: node + linkType: hard + +"@storybook/manager-api@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/manager-api@npm:8.4.6" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: f6deb13cc36852681a54a0a7ec4fed17dab7ae496f07b667e5550950186fd5569b53a21ea0a1416997cda202d47710684bc2da251cb3ea495f59160199e52076 + languageName: node + linkType: hard + +"@storybook/node-logger@npm:^8.0.0-alpha.10": + version: 8.4.5 + resolution: "@storybook/node-logger@npm:8.4.5" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 5b7d49a799def4041d11d70c657bf91bff2d7cda7a6afbfe51d8da58f18c8167b636a99efc749246e1bf76eb29cf6b531ff0a671590e39e4d15fbe179e87287c + languageName: node + linkType: hard + +"@storybook/preset-react-webpack@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/preset-react-webpack@npm:8.4.6" + dependencies: + "@storybook/core-webpack": 8.4.6 + "@storybook/react": 8.4.6 + "@storybook/react-docgen-typescript-plugin": 1.0.6--canary.9.0c3f3b7.0 + "@types/node": ^22.0.0 + "@types/semver": ^7.3.4 + find-up: ^5.0.0 + magic-string: ^0.30.5 + react-docgen: ^7.0.0 + resolve: ^1.22.8 + semver: ^7.3.7 + tsconfig-paths: ^4.2.0 + webpack: 5 + 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.4.6 + peerDependenciesMeta: + typescript: + optional: true + checksum: 90d2e9ce23354117442f8aec01ee4af819d94ec170befe25cf2477e11bdf480c2cbcb3736547f82b58f4261cc78fe47060d635eb1d5138ff317c4d684a00d534 + languageName: node + linkType: hard + +"@storybook/preview-api@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/preview-api@npm:8.4.6" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 9771ea6d3e3a6d48ca926293d6521caeec370f7c51527400ec9d184c9b41c580567f00661a568d66eb5d34b9a7e8703e3c2cc9b1cf91be6acb324d134c7c9f02 + languageName: node + linkType: hard + +"@storybook/react-docgen-typescript-plugin@npm:1.0.6--canary.9.0c3f3b7.0": + version: 1.0.6--canary.9.0c3f3b7.0 + resolution: "@storybook/react-docgen-typescript-plugin@npm:1.0.6--canary.9.0c3f3b7.0" + dependencies: + debug: ^4.1.1 + endent: ^2.0.1 + find-cache-dir: ^3.3.1 + flat-cache: ^3.0.4 + micromatch: ^4.0.2 + react-docgen-typescript: ^2.2.2 + tslib: ^2.0.0 + peerDependencies: + typescript: ">= 4.x" + webpack: ">= 4" + checksum: 38c59c1dd7f9cdf5533e5ffe1991034f563f8d33c59e3cd33fa86719c72f5fe922276fde50315dd24f23f225d1ad5f3a261ecf4c70e82522805d09782272faff + languageName: node + linkType: hard + +"@storybook/react-dom-shim@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/react-dom-shim@npm:8.4.6" + 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.4.6 + checksum: d64daafa29ec8e1cfc29fbfd75ade6ae3287c69d28022cd1d7966bc2cbd75911237cf53db68e5c8c787452e69f36f7ba1aba2f981732684343d16b79cb3c5d07 + languageName: node + linkType: hard + +"@storybook/react-webpack5@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/react-webpack5@npm:8.4.6" + dependencies: + "@storybook/builder-webpack5": 8.4.6 + "@storybook/preset-react-webpack": 8.4.6 + "@storybook/react": 8.4.6 + "@types/node": ^22.0.0 + 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.4.6 + typescript: ">= 4.2.x" + peerDependenciesMeta: + typescript: + optional: true + checksum: 2f030a55c57effc813e242349ce5317e5b425f422af1786d2b4eabc5d7175009223c14b43dced04e2ab9554cde5c886a5318fc4c68fcccdf2cdf5f5eaef24c62 + languageName: node + linkType: hard + +"@storybook/react@npm:8.4.6, @storybook/react@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/react@npm:8.4.6" + dependencies: + "@storybook/components": 8.4.6 + "@storybook/global": ^5.0.0 + "@storybook/manager-api": 8.4.6 + "@storybook/preview-api": 8.4.6 + "@storybook/react-dom-shim": 8.4.6 + "@storybook/theming": 8.4.6 + peerDependencies: + "@storybook/test": 8.4.6 + 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.4.6 + typescript: ">= 4.2.x" + peerDependenciesMeta: + "@storybook/test": + optional: true + typescript: + optional: true + checksum: 43f9cf0d35a1a87c0295305f6eb43be135de86d70b16ba197e474ac854b53b3232c369f392f4023587ec83ce2e9055b0c93e42fd3851e1652f6c5614bafc4827 + languageName: node + linkType: hard + +"@storybook/test@npm:8.4.6, @storybook/test@npm:^8.4.6": + version: 8.4.6 + resolution: "@storybook/test@npm:8.4.6" + dependencies: + "@storybook/csf": ^0.1.11 + "@storybook/global": ^5.0.0 + "@storybook/instrumenter": 8.4.6 + "@testing-library/dom": 10.4.0 + "@testing-library/jest-dom": 6.5.0 + "@testing-library/user-event": 14.5.2 + "@vitest/expect": 2.0.5 + "@vitest/spy": 2.0.5 + peerDependencies: + storybook: ^8.4.6 + checksum: 0d8f1c5cb2d15aa2a86e4beae596b8ce34a34ab09cb4470fcdb6cee7454f60f86166ad0c42a7b1889a29a144c11627a898cf3f838a1fde0c75818c59f7aa6b19 + languageName: node + linkType: hard + +"@storybook/theming@npm:8.4.6": + version: 8.4.6 + resolution: "@storybook/theming@npm:8.4.6" + peerDependencies: + storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 + checksum: 364c7c8d66f523d5dec020157ae5dd86ac976b988f1c61cff61ae141ed906d4c8693f2361eb3b1709409c62f246537e68a3ad6c8d7c7d5c39d7df5bd1c39a815 + languageName: node + linkType: hard + "@sucrase/webpack-loader@npm:^2.0.0": version: 2.0.0 resolution: "@sucrase/webpack-loader@npm:2.0.0" @@ -17372,92 +18786,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-darwin-arm64@npm:1.9.2" +"@swc/core-darwin-arm64@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-darwin-arm64@npm:1.9.3" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-darwin-x64@npm:1.9.2" +"@swc/core-darwin-x64@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-darwin-x64@npm:1.9.3" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.9.2" +"@swc/core-linux-arm-gnueabihf@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.9.3" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm64-gnu@npm:1.9.2" +"@swc/core-linux-arm64-gnu@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm64-gnu@npm:1.9.3" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-arm64-musl@npm:1.9.2" +"@swc/core-linux-arm64-musl@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-arm64-musl@npm:1.9.3" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-x64-gnu@npm:1.9.2" +"@swc/core-linux-x64-gnu@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-x64-gnu@npm:1.9.3" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-linux-x64-musl@npm:1.9.2" +"@swc/core-linux-x64-musl@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-linux-x64-musl@npm:1.9.3" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-arm64-msvc@npm:1.9.2" +"@swc/core-win32-arm64-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-arm64-msvc@npm:1.9.3" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-ia32-msvc@npm:1.9.2" +"@swc/core-win32-ia32-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-ia32-msvc@npm:1.9.3" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.9.2": - version: 1.9.2 - resolution: "@swc/core-win32-x64-msvc@npm:1.9.2" +"@swc/core-win32-x64-msvc@npm:1.9.3": + version: 1.9.3 + resolution: "@swc/core-win32-x64-msvc@npm:1.9.3" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:^1.3.46": - version: 1.9.2 - resolution: "@swc/core@npm:1.9.2" +"@swc/core@npm:^1.3.46, @swc/core@npm:^1.7.3": + version: 1.9.3 + resolution: "@swc/core@npm:1.9.3" dependencies: - "@swc/core-darwin-arm64": 1.9.2 - "@swc/core-darwin-x64": 1.9.2 - "@swc/core-linux-arm-gnueabihf": 1.9.2 - "@swc/core-linux-arm64-gnu": 1.9.2 - "@swc/core-linux-arm64-musl": 1.9.2 - "@swc/core-linux-x64-gnu": 1.9.2 - "@swc/core-linux-x64-musl": 1.9.2 - "@swc/core-win32-arm64-msvc": 1.9.2 - "@swc/core-win32-ia32-msvc": 1.9.2 - "@swc/core-win32-x64-msvc": 1.9.2 + "@swc/core-darwin-arm64": 1.9.3 + "@swc/core-darwin-x64": 1.9.3 + "@swc/core-linux-arm-gnueabihf": 1.9.3 + "@swc/core-linux-arm64-gnu": 1.9.3 + "@swc/core-linux-arm64-musl": 1.9.3 + "@swc/core-linux-x64-gnu": 1.9.3 + "@swc/core-linux-x64-musl": 1.9.3 + "@swc/core-win32-arm64-msvc": 1.9.3 + "@swc/core-win32-ia32-msvc": 1.9.3 + "@swc/core-win32-x64-msvc": 1.9.3 "@swc/counter": ^0.1.3 - "@swc/types": ^0.1.15 + "@swc/types": ^0.1.17 peerDependencies: "@swc/helpers": "*" dependenciesMeta: @@ -17484,7 +18898,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 325afca1473e371804cc420d096553a0c6b19d01296b46b23e3b75a797c8b139c712ad79bc5c876cfc6d7bd6d60014a9f81286a2e888e94f0dec70903893f0b6 + checksum: 4d83aee0b4d9c543f247d680796e5b9cb69997369dcd81642c2603e185312dfb1674328a7ceb1d352c21275155a71789f76dafe8853055d076b6241d5760bbed languageName: node linkType: hard @@ -17517,12 +18931,12 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.15": - version: 0.1.15 - resolution: "@swc/types@npm:0.1.15" +"@swc/types@npm:^0.1.17": + version: 0.1.17 + resolution: "@swc/types@npm:0.1.17" dependencies: "@swc/counter": ^0.1.3 - checksum: 19889eed42d28f5dcef7c16f3b0cf4375890984b106aca46d9455d1f5ba364156d206a8e1f73962718ee408ff9e460b84aaa79025bf8dc30e0d6ded471e1e2d2 + checksum: 6cc87b8ddfb540096abdf40bc29742df0b7d068f97c1ce6c32cd1b7073cde263ed7bc3bae1fba7bf0e1a0f5d63336e9fa092e05a54f6d9b3570df956d2acaff6 languageName: node linkType: hard @@ -17575,7 +18989,7 @@ __metadata: languageName: unknown linkType: soft -"@testing-library/dom@npm:^10.0.0": +"@testing-library/dom@npm:10.4.0, @testing-library/dom@npm:^10.0.0": version: 10.4.0 resolution: "@testing-library/dom@npm:10.4.0" dependencies: @@ -17591,6 +19005,21 @@ __metadata: languageName: node linkType: hard +"@testing-library/jest-dom@npm:6.5.0": + version: 6.5.0 + resolution: "@testing-library/jest-dom@npm:6.5.0" + dependencies: + "@adobe/css-tools": ^4.4.0 + aria-query: ^5.0.0 + chalk: ^3.0.0 + css.escape: ^1.5.1 + dom-accessibility-api: ^0.6.3 + lodash: ^4.17.21 + redent: ^3.0.0 + checksum: c2d14103ebe3358852ec527ff7512f64207a39932b2f7b6dff7e73ba91296b01a71bad9a9584b6ee010681380a906c1740af50470adc6db660e1c7585d012ebf + languageName: node + linkType: hard + "@testing-library/jest-dom@npm:^6.0.0": version: 6.6.3 resolution: "@testing-library/jest-dom@npm:6.6.3" @@ -17648,7 +19077,7 @@ __metadata: languageName: node linkType: hard -"@testing-library/user-event@npm:^14.0.0": +"@testing-library/user-event@npm:14.5.2, @testing-library/user-event@npm:^14.0.0": version: 14.5.2 resolution: "@testing-library/user-event@npm:14.5.2" peerDependencies: @@ -17791,7 +19220,7 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.20.5": +"@types/babel__core@npm:^7.1.14, @types/babel__core@npm:^7.18.0, @types/babel__core@npm:^7.20.5": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" dependencies: @@ -17823,12 +19252,12 @@ __metadata: languageName: node linkType: hard -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.0.15 - resolution: "@types/babel__traverse@npm:7.0.15" +"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6, @types/babel__traverse@npm:^7.18.0": + version: 7.20.6 + resolution: "@types/babel__traverse@npm:7.20.6" dependencies: - "@babel/types": ^7.3.0 - checksum: 6a45519ebf58e6b1197a0177211099fc3ed613d2a435cf9470c39217af35f29013f7984e1f8c2e160a93b588767cfbbcf0d7f77eae399dfcca18d5257f04cbc2 + "@babel/types": ^7.20.7 + checksum: 2bdc65eb62232c2d5c1086adeb0c31e7980e6fd7e50a3483b4a724a1a1029c84d9cb59749cf8de612f9afa2bc14c85b8f50e64e21f8a4398fa77eb9059a4283c languageName: node linkType: hard @@ -17888,6 +19317,15 @@ __metadata: languageName: node linkType: hard +"@types/cacheable-request@npm:^8.3.6": + version: 8.3.6 + resolution: "@types/cacheable-request@npm:8.3.6" + dependencies: + cacheable-request: "*" + checksum: e6046beb3d74a21484f365052a740d000695548dc6d01923350a087bb1530f6361a8a2948cd16ea2176f5f4a3b907fc84a8aa3fd5ad9ea13e62ced28dc65693f + languageName: node + linkType: hard + "@types/caseless@npm:*": version: 0.12.2 resolution: "@types/caseless@npm:0.12.2" @@ -17983,11 +19421,11 @@ __metadata: linkType: hard "@types/cookie-parser@npm:^1.4.2": - version: 1.4.7 - resolution: "@types/cookie-parser@npm:1.4.7" - dependencies: + version: 1.4.8 + resolution: "@types/cookie-parser@npm:1.4.8" + peerDependencies: "@types/express": "*" - checksum: 7b87c59420598e686a57e240be6e0db53967c3c8814be9326bf86609ee2fc39c4b3b9f2263e1deba43526090121d1df88684b64c19f7b494a80a4437caf3d40b + checksum: b26ace5560adce1a746c059a75f18227ee3e3614a49c70dd29b8af204696079ced22eaa9d6cb084e3433ec433bff845cb47ffb890ae9af96a4aab2ff85e40da7 languageName: node linkType: hard @@ -18113,13 +19551,20 @@ __metadata: linkType: hard "@types/dockerode@npm:^3.3.0, @types/dockerode@npm:^3.3.29": - version: 3.3.31 - resolution: "@types/dockerode@npm:3.3.31" + version: 3.3.32 + resolution: "@types/dockerode@npm:3.3.32" dependencies: "@types/docker-modem": "*" "@types/node": "*" "@types/ssh2": "*" - checksum: f634f18dc0633f8324faefcde53bcd3d8f3c4bd74d31078cbeb65d2e1597f9abcf12c2158abfaea13dc816bae0f5fa08d0bb570d4214ab0df1ded90db5ebabfe + checksum: 17bfa92511cdc6ab51a67cb4678931b43670feffd737ba593c3ff90a6f71673aa04f8a81524690dddc08b483628d657a338a176171ff131de9e0efba4c3ecc11 + languageName: node + linkType: hard + +"@types/doctrine@npm:^0.0.9": + version: 0.0.9 + resolution: "@types/doctrine@npm:0.0.9" + checksum: 3909eaca42e7386b2ab866f082b78da3e00718d2fa323597e254feb0556c678b41f2c490729067433630083ac9c806ec6ae1e146754f7f8ba7d3e43ed68d6500 languageName: node linkType: hard @@ -18155,7 +19600,17 @@ __metadata: languageName: node linkType: hard -"@types/eslint@npm:^8.56.10": +"@types/eslint-scope@npm:^3.7.7": + version: 3.7.7 + resolution: "@types/eslint-scope@npm:3.7.7" + dependencies: + "@types/eslint": "*" + "@types/estree": "*" + checksum: e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e + languageName: node + linkType: hard + +"@types/eslint@npm:*, @types/eslint@npm:^8.56.10": version: 8.56.12 resolution: "@types/eslint@npm:8.56.12" dependencies: @@ -18165,7 +19620,7 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": +"@types/estree@npm:*, @types/estree@npm:1.0.6, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5, @types/estree@npm:^1.0.6": version: 1.0.6 resolution: "@types/estree@npm:1.0.6" checksum: 8825d6e729e16445d9a1dd2fb1db2edc5ed400799064cd4d028150701031af012ba30d6d03fe9df40f4d7a437d0de6d2b256020152b7b09bde9f2e420afdffd9 @@ -18211,11 +19666,11 @@ __metadata: linkType: hard "@types/express-session@npm:^1.17.2": - version: 1.18.0 - resolution: "@types/express-session@npm:1.18.0" + version: 1.18.1 + resolution: "@types/express-session@npm:1.18.1" dependencies: "@types/express": "*" - checksum: f624bc956d223eda618dc3ee5908cfc91d5cf67252aa83e667c1260b96c2d2ac302407d57d2a57b29728a21bf521f09c6409da5e727509c01a2b50d7a012f0a1 + checksum: 380ddcbbc6a64686deafd4e2831c636d11a3252f051ebb4c49649abfab5ddf69c2b31e4ff97a2961cb02ef8c616feaa7ecaa4ad7b7f028c25d88fbfa437fb455 languageName: node linkType: hard @@ -18316,10 +19771,10 @@ __metadata: languageName: node linkType: hard -"@types/http-cache-semantics@npm:*": - version: 4.0.0 - resolution: "@types/http-cache-semantics@npm:4.0.0" - checksum: c820774eb1d9d8d0c13077834e870cc1afd2500dc9d0ac1b67abc050c7c115aee4024f90fda65b50babc258de0464fc4459709e4fa12552f65094328e5a551c6 +"@types/http-cache-semantics@npm:*, @types/http-cache-semantics@npm:^4.0.4": + version: 4.0.4 + resolution: "@types/http-cache-semantics@npm:4.0.4" + checksum: 7f4dd832e618bc1e271be49717d7b4066d77c2d4eed5b81198eb987e532bb3e1c7e02f45d77918185bad936f884b700c10cebe06305f50400f382ab75055f9e8 languageName: node linkType: hard @@ -18584,6 +20039,13 @@ __metadata: languageName: node linkType: hard +"@types/mdx@npm:^2.0.0": + version: 2.0.13 + resolution: "@types/mdx@npm:2.0.13" + checksum: 195137b548e75a85f0558bb1ca5088aff1c01ae0fc64454da06085b7513a043356d0bb51ed559d3cbc7ad724ccd8cef2a7d07d014b89a47a74dff8875ceb3b15 + languageName: node + linkType: hard + "@types/memcached@npm:^2.2.6": version: 2.2.10 resolution: "@types/memcached@npm:2.2.10" @@ -18593,6 +20055,15 @@ __metadata: languageName: node linkType: hard +"@types/memjs@npm:^1.3.3": + version: 1.3.3 + resolution: "@types/memjs@npm:1.3.3" + dependencies: + "@types/node": "*" + checksum: 23efd3196a6318b251ebbcebef03f737aa609ff467430348dad540aec5db58e49b291b40df743f19f9182bfbe7f06fb6244aaecc28513b4f27728ed2117a1b21 + languageName: node + linkType: hard + "@types/mime-types@npm:^2.1.0": version: 2.1.4 resolution: "@types/mime-types@npm:2.1.4" @@ -18672,7 +20143,7 @@ __metadata: languageName: node linkType: hard -"@types/node-fetch@npm:^2.5.12, @types/node-fetch@npm:^2.6.4, @types/node-fetch@npm:^2.6.9": +"@types/node-fetch@npm:^2.6.4, @types/node-fetch@npm:^2.6.9": version: 2.6.12 resolution: "@types/node-fetch@npm:2.6.12" dependencies: @@ -18692,11 +20163,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:>=13.7.0, @types/node@npm:^22.0.0": - version: 22.8.7 - resolution: "@types/node@npm:22.8.7" + version: 22.10.2 + resolution: "@types/node@npm:22.10.2" dependencies: - undici-types: ~6.19.8 - checksum: c7b200d06da97a4d4f46528ae962c028bb06b6ef9ab7f7949639420f3b3d236f041756ca1945dcaec0fcefbafd07b8ca47bbc1b47b77d33a4173211425641426 + undici-types: ~6.20.0 + checksum: b22401e6e7d1484e437d802c72f5560e18100b1257b9ad0574d6fe05bebe4dbcb620ea68627d1f1406775070d29ace8b6b51f57e7b1c7b8bafafe6da7f29c843 languageName: node linkType: hard @@ -18722,29 +20193,29 @@ __metadata: linkType: hard "@types/node@npm:^18.11.18, @types/node@npm:^18.11.9, @types/node@npm:^18.17.15": - version: 18.19.64 - resolution: "@types/node@npm:18.19.64" + version: 18.19.68 + resolution: "@types/node@npm:18.19.68" dependencies: undici-types: ~5.26.4 - checksum: e7680215b03c9bee8a33947f03d06048e8e460f23b1b7b29c45350cf437faa5f8fcb7d8c3eb8dfec8427923e7a184df42bc710c1b6252b4852e3ed7064c6228f + checksum: 84e1cd61b719405aa3b9cc42fbdd8821696684150be04cbd35ebed3b92363a83e904cd89dec5b50dd6a8ff0ea9f26c60436109900b485dbd5b93a81fd6374ccb languageName: node linkType: hard "@types/node@npm:^20.1.1, @types/node@npm:^20.16.0": - version: 20.17.6 - resolution: "@types/node@npm:20.17.6" + version: 20.17.10 + resolution: "@types/node@npm:20.17.10" dependencies: undici-types: ~6.19.2 - checksum: d51dbb9881c94d0310b32b5fd8013e3261595c61bc888fa27258469c93c3dc0b3c4d20a9f28f3f5f79562f6737e28e7f3dd04940dc8b4d966d34aaf318f7f69b + checksum: 44cfa7cd9a4ebb8f74efa4b89cf963ca0e522121a7d24d8121d40872bbcfd607eaccdc203c4fe92c8b587125be9ca7b071fe4f9b356f263434b8a8512dbebef0 languageName: node linkType: hard "@types/nodemailer@npm:^6.4.14": - version: 6.4.16 - resolution: "@types/nodemailer@npm:6.4.16" + version: 6.4.17 + resolution: "@types/nodemailer@npm:6.4.17" dependencies: "@types/node": "*" - checksum: ef34226b7b69a474a9b9b4681bcfb2461540aed92c54995b934f8072e28deff72aadd4c71522f6825938346048cfec077c69f18cfc2a3ec9f7432db11e5667a3 + checksum: 498b702575111494a42cf9cdd3d399f0308c3b3b0244e7f53008924327955a16b39ba0bf99a5ccf17af9fd2bc50a61a76ae7e8a75498a426ea2f828a05202eab languageName: node linkType: hard @@ -18918,14 +20389,14 @@ __metadata: languageName: node 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.13 - resolution: "@types/prop-types@npm:15.7.13" - checksum: 8935cad87c683c665d09a055919d617fe951cb3b2d5c00544e3a913f861a2bd8d2145b51c9aa6d2457d19f3107ab40784c40205e757232f6a80cc8b1c815513c +"@types/prop-types@npm:*, @types/prop-types@npm:^15.0.0, @types/prop-types@npm:^15.7.12, @types/prop-types@npm:^15.7.13, @types/prop-types@npm:^15.7.3": + version: 15.7.14 + resolution: "@types/prop-types@npm:15.7.14" + checksum: d0c5407b9ccc3dd5fae0ccf9b1007e7622ba5e6f1c18399b4f24dff33619d469da4b9fa918a374f19dc0d9fe6a013362aab0b844b606cfc10676efba3f5f736d languageName: node linkType: hard -"@types/protocol-buffers-schema@npm:^3.4.1": +"@types/protocol-buffers-schema@npm:^3.4.3": version: 3.4.3 resolution: "@types/protocol-buffers-schema@npm:3.4.3" dependencies: @@ -18958,11 +20429,11 @@ __metadata: linkType: hard "@types/react-dom@npm:^18": - version: 18.3.1 - resolution: "@types/react-dom@npm:18.3.1" - dependencies: - "@types/react": "*" - checksum: ad28ecce3915d30dc76adc2a1373fda1745ba429cea290e16c6628df9a05fd80b6403c8e87d78b45e6c60e51df7a67add389ab62b90070fbfdc9bda8307d9953 + version: 18.3.5 + resolution: "@types/react-dom@npm:18.3.5" + peerDependencies: + "@types/react": ^18.0.0 + checksum: 95c757684f71e761515c5a11299e5feec550c72bb52975487f360e6f0d359b26454c26eaf2ce45dd22748205aa9b2c2fe0abe7005ebcbd233a7615283ac39a7d languageName: node linkType: hard @@ -19060,12 +20531,12 @@ __metadata: linkType: hard "@types/react@npm:^18": - version: 18.3.12 - resolution: "@types/react@npm:18.3.12" + version: 18.3.17 + resolution: "@types/react@npm:18.3.17" dependencies: "@types/prop-types": "*" csstype: ^3.0.2 - checksum: 4ab1577a8c2105a5e316536f724117c90eee5f4bd5c137fc82a2253d8c1fd299dedaa07e8dfc95d6e2f04a4be3cb8b0e1b06098c6233ebd55c508d88099395b7 + checksum: 8107f6f5cc8706a3814e6c927e135ce0c7b40a6d9ae2b8dfb071fee03c6f714456041ecdf92dece599da0db8be7f56f6dc6353d4701f47a04772c7ec0cbb0b59 languageName: node linkType: hard @@ -19106,6 +20577,13 @@ __metadata: languageName: node linkType: hard +"@types/resolve@npm:^1.20.2": + version: 1.20.6 + resolution: "@types/resolve@npm:1.20.6" + checksum: dc35f5517606b6687cd971c0281ac58bdee2c50c051b030f04647d3991688be2259c304ee97e5b5d4b9936072c36767eb5933b54611a407d6557972bb6fea4f6 + languageName: node + linkType: hard + "@types/responselike@npm:*, @types/responselike@npm:^1.0.0": version: 1.0.0 resolution: "@types/responselike@npm:1.0.0" @@ -19154,7 +20632,7 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:7.5.8, @types/semver@npm:^7.1.0, @types/semver@npm:^7.3.12, @types/semver@npm:^7.5.0": +"@types/semver@npm:7.5.8, @types/semver@npm:^7.1.0, @types/semver@npm:^7.3.12, @types/semver@npm:^7.3.4, @types/semver@npm:^7.5.0": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" checksum: ea6f5276f5b84c55921785a3a27a3cd37afee0111dfe2bcb3e03c31819c197c782598f17f0b150a69d453c9584cd14c4c4d7b9a55d2c5e6cacd4d66fdb3b3663 @@ -19447,6 +20925,13 @@ __metadata: languageName: node linkType: hard +"@types/uuid@npm:^9.0.1": + version: 9.0.8 + resolution: "@types/uuid@npm:9.0.8" + checksum: b8c60b7ba8250356b5088302583d1704a4e1a13558d143c549c408bf8920535602ffc12394ede77f8a8083511b023704bc66d1345792714002bfa261b17c5275 + languageName: node + linkType: hard + "@types/vinyl@npm:^2.0.4": version: 2.0.6 resolution: "@types/vinyl@npm:2.0.6" @@ -19631,13 +21116,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.5.0": - version: 8.5.0 - resolution: "@typescript-eslint/scope-manager@npm:8.5.0" +"@typescript-eslint/scope-manager@npm:8.16.0": + version: 8.16.0 + resolution: "@typescript-eslint/scope-manager@npm:8.16.0" dependencies: - "@typescript-eslint/types": 8.5.0 - "@typescript-eslint/visitor-keys": 8.5.0 - checksum: ee210599652cd21df39467c2b0eeecf97fceb13cf3402e2c11eb47ee4fe1ec9caacba7dedc0917a62febd607bd3517c6ff3a179074c7d2ac4db412d3ea7f392c + "@typescript-eslint/types": 8.16.0 + "@typescript-eslint/visitor-keys": 8.16.0 + checksum: 12427e2a95a8b0cb49259be1a8a9a23f734fd0dbabbc5cebf1ba56b48812e2ca7ba32b71ededf24efa1a9da07a13b20ced004e2eea6f4b8c07003438f664ce30 languageName: node linkType: hard @@ -19672,10 +21157,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:8.5.0": - version: 8.5.0 - resolution: "@typescript-eslint/types@npm:8.5.0" - checksum: 74a7ec57f867f02e1c957763a0db3f0f29d41293abb0fc1e067f4de404c0c4e07d7126fff7a10a4e1ccb9ebd45351dd7709dad42367a9defaa9a411ed1b8e29d +"@typescript-eslint/types@npm:8.16.0": + version: 8.16.0 + resolution: "@typescript-eslint/types@npm:8.16.0" + checksum: 1ed10343dc65c7fd493cfe789639f547f4c730e6e04472007fa92a00ff1fb77b31fc8016a350a10e553d38b12485f78c331d91c071dc08f69476076f5bbef5cd languageName: node linkType: hard @@ -19716,12 +21201,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.5.0": - version: 8.5.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.5.0" +"@typescript-eslint/typescript-estree@npm:8.16.0": + version: 8.16.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.16.0" dependencies: - "@typescript-eslint/types": 8.5.0 - "@typescript-eslint/visitor-keys": 8.5.0 + "@typescript-eslint/types": 8.16.0 + "@typescript-eslint/visitor-keys": 8.16.0 debug: ^4.3.4 fast-glob: ^3.3.2 is-glob: ^4.0.3 @@ -19731,7 +21216,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: e8a4d2fc560ab9084c4cafa7933ce17ca9906c88610282507a54c509dea4c03c00182880e34396cfb3b643264d032620dfe14ceba7cc03022ad0fd4213c5548d + checksum: 047ae08a7774e4be4307409970d7b8b27d46d10e302ed236199b1b7648242d2aa10b7d1dbeae1fed0f55f683c863f9d399e50108c215e35370fb6a3851bda427 languageName: node linkType: hard @@ -19770,17 +21255,20 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0": - version: 8.5.0 - resolution: "@typescript-eslint/utils@npm:8.5.0" +"@typescript-eslint/utils@npm:^6.0.0 || ^7.0.0 || ^8.0.0, @typescript-eslint/utils@npm:^8.8.1": + version: 8.16.0 + resolution: "@typescript-eslint/utils@npm:8.16.0" dependencies: "@eslint-community/eslint-utils": ^4.4.0 - "@typescript-eslint/scope-manager": 8.5.0 - "@typescript-eslint/types": 8.5.0 - "@typescript-eslint/typescript-estree": 8.5.0 + "@typescript-eslint/scope-manager": 8.16.0 + "@typescript-eslint/types": 8.16.0 + "@typescript-eslint/typescript-estree": 8.16.0 peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: d91d4f29aa3275e35734dbf84dfdb2e0e5557c2ed4181e760b3d9319379f19295a79d223b06f5f3583e4de80938dfe47814a11b7fd66a737b5ca6bbe6a555632 + peerDependenciesMeta: + typescript: + optional: true + checksum: 5e3c4b4d453bee6c38715f851d517ad3bbdb9335de5c2ef487e350eea97ae8b2e996046a1d8f3a93109e06a569d1e161b4ef8d33c530766931e4dbc43cb26ed7 languageName: node linkType: hard @@ -19804,13 +21292,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.5.0": - version: 8.5.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.5.0" +"@typescript-eslint/visitor-keys@npm:8.16.0": + version: 8.16.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.16.0" dependencies: - "@typescript-eslint/types": 8.5.0 - eslint-visitor-keys: ^3.4.3 - checksum: dbba7071e9723d0e525d8b350834d95699037e9e7ba9cf2b3b4fb6cf3fd47072869874f665daca54bc084c910a4ae0acfd5670625a4cc62a173662b09f92e79e + "@typescript-eslint/types": 8.16.0 + eslint-visitor-keys: ^4.2.0 + checksum: e7444d3d57b4fcdebfa0d7effcdff9c928d77b6a6765da6980f0dbeb6438af707bd4c2c21e24e7ae1638f9c4a5697168f94027fff94ad663da57fa5f44f0983d languageName: node linkType: hard @@ -20079,18 +21567,120 @@ __metadata: languageName: node linkType: hard -"@vitejs/plugin-react@npm:^4.3.1": - version: 4.3.3 - resolution: "@vitejs/plugin-react@npm:4.3.3" +"@vanilla-extract/babel-plugin-debug-ids@npm:^1.1.0": + version: 1.1.0 + resolution: "@vanilla-extract/babel-plugin-debug-ids@npm:1.1.0" dependencies: - "@babel/core": ^7.25.2 - "@babel/plugin-transform-react-jsx-self": ^7.24.7 - "@babel/plugin-transform-react-jsx-source": ^7.24.7 + "@babel/core": ^7.23.9 + checksum: b2feec9016ba2dd6740c2ce002d814123f38bf8fc01a6d771eff74ed8108abefdc9d6507e2045587d2a73d8a538ece867e4bfef8c5ccc2b13095a2c825160e7a + languageName: node + linkType: hard + +"@vanilla-extract/css@npm:^1.16.1": + version: 1.16.1 + resolution: "@vanilla-extract/css@npm:1.16.1" + dependencies: + "@emotion/hash": ^0.9.0 + "@vanilla-extract/private": ^1.0.6 + css-what: ^6.1.0 + cssesc: ^3.0.0 + csstype: ^3.0.7 + dedent: ^1.5.3 + deep-object-diff: ^1.1.9 + deepmerge: ^4.2.2 + lru-cache: ^10.4.3 + media-query-parser: ^2.0.2 + modern-ahocorasick: ^1.0.0 + picocolors: ^1.0.0 + checksum: ff58f32778cbc15458aff951ad771ba46f772d78633ff99f849f590b83a22ce67e017af28351c68c32edcdaae4454146dd90f369842a627ee79dc9c3ab434e1e + languageName: node + linkType: hard + +"@vanilla-extract/integration@npm:^7.1.11": + version: 7.1.11 + resolution: "@vanilla-extract/integration@npm:7.1.11" + dependencies: + "@babel/core": ^7.23.9 + "@babel/plugin-syntax-typescript": ^7.23.3 + "@vanilla-extract/babel-plugin-debug-ids": ^1.1.0 + "@vanilla-extract/css": ^1.16.1 + dedent: ^1.5.3 + esbuild: "npm:esbuild@>=0.17.6 <0.24.0" + eval: 0.1.8 + find-up: ^5.0.0 + javascript-stringify: ^2.0.1 + mlly: ^1.4.2 + vite: ^5.0.11 + vite-node: ^1.2.0 + checksum: 23196f388045c0cdaa35bf26cf484ca4423e336026770b743017056aed7704c74c2134b425571eee9c6859ed1a1553a435e4d0c502ff5a78f8dc2c02db00707a + languageName: node + linkType: hard + +"@vanilla-extract/private@npm:^1.0.6": + version: 1.0.6 + resolution: "@vanilla-extract/private@npm:1.0.6" + checksum: 2265b02af29d8cd40f6ddeeed197fb2df1a7695f5a9821d5e3597677179be8b83bcd8fe4df4a6178544f89123d745a3c6a13599d4fe4e5873b065a8ad329f690 + languageName: node + linkType: hard + +"@vanilla-extract/rollup-plugin@npm:^1.3.10": + version: 1.3.11 + resolution: "@vanilla-extract/rollup-plugin@npm:1.3.11" + dependencies: + "@vanilla-extract/integration": ^7.1.11 + peerDependencies: + rollup: ^2.0.0 || ^3.0.0 || ^4.0.0 + checksum: 2e38981d156f8db962dedfc64131adbe8bd5ec9236686dccec92f3418d43d658f2f3a5797456f67eeb43ce75dcc84f9593e4f073e0e42c6df31d4e3ba6a59785 + languageName: node + linkType: hard + +"@vanilla-extract/sprinkles@npm:^1.6.3": + version: 1.6.3 + resolution: "@vanilla-extract/sprinkles@npm:1.6.3" + peerDependencies: + "@vanilla-extract/css": ^1.0.0 + checksum: 7eb4fe0f1a6048bf5ffb5ffab964c2d127ff95244da79dca2e448af380b591c7af3b4f63ab243584baa8a42c7694d8fe9eeb366587a2da381a481fe1a9e02af8 + languageName: node + linkType: hard + +"@vanilla-extract/webpack-plugin@npm:^2.3.14": + version: 2.3.15 + resolution: "@vanilla-extract/webpack-plugin@npm:2.3.15" + dependencies: + "@vanilla-extract/integration": ^7.1.11 + debug: ^4.3.1 + loader-utils: ^2.0.0 + picocolors: ^1.0.0 + peerDependencies: + webpack: ^4.30.0 || ^5.20.2 + checksum: 105540377d0eb19f8dafcd2cc2cf893471494d4b82012574d4b70c32351ef78b6107ffaecf188a7a6edc10e70bd2963c4fd13ff16954f8063bb785aab98070dd + languageName: node + linkType: hard + +"@vitejs/plugin-react@npm:^4.3.1": + version: 4.3.4 + resolution: "@vitejs/plugin-react@npm:4.3.4" + dependencies: + "@babel/core": ^7.26.0 + "@babel/plugin-transform-react-jsx-self": ^7.25.9 + "@babel/plugin-transform-react-jsx-source": ^7.25.9 "@types/babel__core": ^7.20.5 react-refresh: ^0.14.2 peerDependencies: - vite: ^4.2.0 || ^5.0.0 - checksum: 1ad449cb7934e14ad265a0044aa2461cdb47587c436c2a0324e2b6a73de1b63a34a84396de41b77988fac67ff43302bf0186674344e11a881ba50936cc4297d8 + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + checksum: d417f40d9259a1d5193152f7d9fee081d5bf41cbeef9662ae1123ccc1e26aa4b6b04bc82ebb8c4fbfde9516a746fb3af7da19fdd449819c30f0631daaa10a44b + languageName: node + linkType: hard + +"@vitest/expect@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/expect@npm:2.0.5" + dependencies: + "@vitest/spy": 2.0.5 + "@vitest/utils": 2.0.5 + chai: ^5.1.1 + tinyrainbow: ^1.2.0 + checksum: 0c65eb24c2fd9ef5735d1e65dc8fee59936e6cab1d6ab24a95e014b8337be5598242fceae4e8ec2974e2ae70a30c1906ad41208bf6de6cdf2043594cdb65e627 languageName: node linkType: hard @@ -20106,6 +21696,15 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/pretty-format@npm:2.0.5" + dependencies: + tinyrainbow: ^1.2.0 + checksum: d60346001180e5bb3c53be4b4d0b6d9352648b066641d5aba7b97d7c97a8e252dc934204d58818330262a65f07127455fc5f3b5f7e3647c60f6ff302a725733b + languageName: node + linkType: hard + "@vitest/pretty-format@npm:2.1.3": version: 2.1.3 resolution: "@vitest/pretty-format@npm:2.1.3" @@ -20115,6 +21714,24 @@ __metadata: languageName: node linkType: hard +"@vitest/pretty-format@npm:2.1.6": + version: 2.1.6 + resolution: "@vitest/pretty-format@npm:2.1.6" + dependencies: + tinyrainbow: ^1.2.0 + checksum: 4cab9152ac97fa190db85bbe7e1ae8f1b5d2312fa3ccf7e813119933b2aaf4c763c6156a6d91cb186d3ed4be81f5bb70da2c731fde2d12457fe0871087d2be74 + languageName: node + linkType: hard + +"@vitest/spy@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/spy@npm:2.0.5" + dependencies: + tinyspy: ^3.0.0 + checksum: a010dec99146832a2586c639fccf533b194482f6f25ffb2d64367598a4e77d094aedd3d82cdb55fc1a3971649577a039513ccf8dc1571492e5982482c530c7b9 + languageName: node + linkType: hard + "@vitest/spy@npm:2.1.3": version: 2.1.3 resolution: "@vitest/spy@npm:2.1.3" @@ -20124,6 +21741,18 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:2.0.5": + version: 2.0.5 + resolution: "@vitest/utils@npm:2.0.5" + dependencies: + "@vitest/pretty-format": 2.0.5 + estree-walker: ^3.0.3 + loupe: ^3.1.1 + tinyrainbow: ^1.2.0 + checksum: 6867556dd7e376437e454b96c7e596ec16e141fb00b002b6ce435611ab3d9d1e3f38ebf48b1fc49f4c97f9754ed37abb602de8bf122f4ac0de621a4dbe0a314e + languageName: node + linkType: hard + "@vitest/utils@npm:2.1.3": version: 2.1.3 resolution: "@vitest/utils@npm:2.1.3" @@ -20135,6 +21764,17 @@ __metadata: languageName: node linkType: hard +"@vitest/utils@npm:^2.1.1": + version: 2.1.6 + resolution: "@vitest/utils@npm:2.1.6" + dependencies: + "@vitest/pretty-format": 2.1.6 + loupe: ^3.1.2 + tinyrainbow: ^1.2.0 + checksum: 8b9c994eccb724d76128e875e8438d519bfae0126e7431e8682e7f07d9faeff929db1afa2742b188883e42508d4cdcb2326f9ae27c1b53b5f746d283a9e75462 + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.12.1, @webassemblyjs/ast@npm:^1.12.1": version: 1.12.1 resolution: "@webassemblyjs/ast@npm:1.12.1" @@ -21047,12 +22687,12 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": - version: 8.11.3 - resolution: "acorn@npm:8.11.3" +"acorn@npm:^8.14.0, acorn@npm:^8.4.1, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.14.0 + resolution: "acorn@npm:8.14.0" bin: acorn: bin/acorn - checksum: 76d8e7d559512566b43ab4aadc374f11f563f0a9e21626dd59cb2888444e9445923ae9f3699972767f18af61df89cd89f5eaaf772d1327b055b45cb829b4a88c + checksum: 8755074ba55fff94e84e81c72f1013c2d9c78e973c31231c8ae505a5f966859baf654bddd75046bffd73ce816b149298977fff5077a3033dedba0ae2aad152d4 languageName: node linkType: hard @@ -21079,12 +22719,10 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: ^4.3.4 - checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037 +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 87bb7ee54f5ecf0ccbfcba0b07473885c43ecd76cb29a8db17d6137a19d9f9cd443a2a7c5fd8a3f24d58ad8145f9eb49116344a66b107e1aeab82cf2383f4753 languageName: node linkType: hard @@ -21313,7 +22951,7 @@ __metadata: languageName: node linkType: hard -"ansi-html-community@npm:^0.0.8": +"ansi-html-community@npm:0.0.8, ansi-html-community@npm:^0.0.8": version: 0.0.8 resolution: "ansi-html-community@npm:0.0.8" bin: @@ -22007,7 +23645,7 @@ __metadata: languageName: node linkType: hard -"axios@npm:1.7.7, axios@npm:^1.0.0, axios@npm:^1.6.0, axios@npm:^1.7.4, axios@npm:^1.7.7": +"axios@npm:1.7.7": version: 1.7.7 resolution: "axios@npm:1.7.7" dependencies: @@ -22018,6 +23656,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": + version: 1.7.9 + resolution: "axios@npm:1.7.9" + dependencies: + follow-redirects: ^1.15.6 + form-data: ^4.0.0 + proxy-from-env: ^1.1.0 + checksum: cb8ce291818effda09240cb60f114d5625909b345e10f389a945320e06acf0bc949d0f8422d25720f5dd421362abee302c99f5e97edec4c156c8939814b23d19 + languageName: node + linkType: hard + "axobject-query@npm:^4.1.0": version: 4.1.0 resolution: "axobject-query@npm:4.1.0" @@ -22347,6 +23996,15 @@ __metadata: languageName: node linkType: hard +"better-opn@npm:^3.0.2": + version: 3.0.2 + resolution: "better-opn@npm:3.0.2" + dependencies: + open: ^8.0.4 + checksum: 1471552fa7f733561e7f49e812be074b421153006ca744de985fb6d38939807959fc5fe9cb819cf09f864782e294704fd3b31711ea14c115baf3330a2f1135de + languageName: node + linkType: hard + "better-path-resolve@npm:1.0.0": version: 1.0.0 resolution: "better-path-resolve@npm:1.0.0" @@ -22357,13 +24015,13 @@ __metadata: linkType: hard "better-sqlite3@npm:^11.0.0": - version: 11.5.0 - resolution: "better-sqlite3@npm:11.5.0" + version: 11.6.0 + resolution: "better-sqlite3@npm:11.6.0" dependencies: bindings: ^1.5.0 node-gyp: latest prebuild-install: ^7.1.1 - checksum: 37acef8d4272ad57fe211aa5a2e177f95443eafb794c7db6c2d0dae0a4fe4c2ef508b8b970d82f1d9744d009677d82067279f45e27d4155a5e68a578f5c5c051 + checksum: 4570559e8b62da295060b086cfe7902648670863790993be1a43e73867f3d9767598aa52fb8332cf3eb16aa30f3037c3705ce5a195db59c076006067e43eea98 languageName: node linkType: hard @@ -22600,6 +24258,13 @@ __metadata: languageName: node linkType: hard +"browser-assert@npm:^1.2.1": + version: 1.2.1 + resolution: "browser-assert@npm:1.2.1" + checksum: 8b2407cd04c1ed592cf892dec35942b7d72635829221e0788c9a16c4d2afa8b7156bc9705b1c4b32c30d88136c576fda3cbcb8f494d6f865264c706ea8798d92 + languageName: node + linkType: hard + "browser-headers@npm:^0.4.1": version: 0.4.1 resolution: "browser-headers@npm:0.4.1" @@ -22696,17 +24361,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.23.1": - version: 4.23.3 - resolution: "browserslist@npm:4.23.3" +"browserslist@npm:^4.0.0, browserslist@npm:^4.16.0, browserslist@npm:^4.16.6, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.24.0": + version: 4.24.2 + resolution: "browserslist@npm:4.24.2" dependencies: - caniuse-lite: ^1.0.30001646 - electron-to-chromium: ^1.5.4 + caniuse-lite: ^1.0.30001669 + electron-to-chromium: ^1.5.41 node-releases: ^2.0.18 - update-browserslist-db: ^1.1.0 + update-browserslist-db: ^1.1.1 bin: browserslist: cli.js - checksum: 7906064f9970aeb941310b2fcb8b4ace4a1b50aa657c986677c6f1553a8cabcc94ee9c5922f715baffbedaa0e6cf0831b6fed7b059dde6873a4bfadcbe069c7e + checksum: cf64085f12132d38638f38937a255edb82c7551b164a98577b055dd79719187a816112f7b97b9739e400c4954cd66479c0d7a843cb816e346f4795dc24fd5d97 languageName: node linkType: hard @@ -22871,6 +24536,13 @@ __metadata: languageName: node linkType: hard +"cac@npm:^6.7.14": + version: 6.7.14 + resolution: "cac@npm:6.7.14" + checksum: 45a2496a9443abbe7f52a49b22fbe51b1905eff46e03fd5e6c98e3f85077be3f8949685a1849b1a9cd2bc3e5567dfebcf64f01ce01847baf918f1b37c839791a + languageName: node + linkType: hard + "cacache@npm:^15.0.3, cacache@npm:^15.0.5, cacache@npm:^15.2.0": version: 15.3.0 resolution: "cacache@npm:15.3.0" @@ -22943,6 +24615,26 @@ __metadata: languageName: node linkType: hard +"cacache@npm:^19.0.1": + version: 19.0.1 + resolution: "cacache@npm:19.0.1" + dependencies: + "@npmcli/fs": ^4.0.0 + fs-minipass: ^3.0.0 + glob: ^10.2.2 + lru-cache: ^10.0.1 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + p-map: ^7.0.2 + ssri: ^12.0.0 + tar: ^7.4.3 + unique-filename: ^4.0.0 + checksum: e95684717de6881b4cdaa949fa7574e3171946421cd8291769dd3d2417dbf7abf4aa557d1f968cca83dcbc95bed2a281072b09abfc977c942413146ef7ed4525 + languageName: node + linkType: hard + "cache-content-type@npm:^1.0.0": version: 1.0.1 resolution: "cache-content-type@npm:1.0.1" @@ -22967,6 +24659,21 @@ __metadata: languageName: node linkType: hard +"cacheable-request@npm:*": + version: 13.0.2 + resolution: "cacheable-request@npm:13.0.2" + dependencies: + "@types/http-cache-semantics": ^4.0.4 + get-stream: ^9.0.1 + http-cache-semantics: ^4.1.1 + keyv: ^5.2.1 + mimic-response: ^4.0.0 + normalize-url: ^8.0.1 + responselike: ^3.0.0 + checksum: b019639ddbd617eced8933882c4a15d3de8a51ab2f90fddae860812951c5f5271f293696bd4cf37f6605e73239fca37cff1c8a32d01aa28a27fd685a66aa590a + languageName: node + linkType: hard + "cacheable-request@npm:^6.0.0": version: 6.1.0 resolution: "cacheable-request@npm:6.1.0" @@ -23074,10 +24781,17 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001616, caniuse-lite@npm:^1.0.30001646": - version: 1.0.30001668 - resolution: "caniuse-lite@npm:1.0.30001668" - checksum: ce6996901b5883454a8ddb3040f82342277b6a6275876dfefcdecb11f7e472e29877f34cae47c2b674f08f2e71971dd4a2acb9bc01adfe8421b7148a7e9e8297 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001616, caniuse-lite@npm:^1.0.30001669": + version: 1.0.30001684 + resolution: "caniuse-lite@npm:1.0.30001684" + checksum: 5ee7aca9c29067d2e4c88cd05cbc062599d86389cd99e26e4d4bf84de8fad3f9ed2be9d3d909dfb65f50e77a17192175cb132eca7f0988ab0f3e8c4aa0dccd38 + languageName: node + linkType: hard + +"case-sensitive-paths-webpack-plugin@npm:^2.4.0": + version: 2.4.0 + resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0" + checksum: bcf469446eeee9ac0046e30860074ebb9aa4803aab9140e6bb72b600b23b1d70635690754be4504ce35cd99cdf05226bee8d894ba362a3f5485d5f6310fc6d02 languageName: node linkType: hard @@ -23263,6 +24977,25 @@ __metadata: languageName: node linkType: hard +"chromatic@npm:^11.15.0": + version: 11.19.0 + resolution: "chromatic@npm:11.19.0" + peerDependencies: + "@chromatic-com/cypress": ^0.*.* || ^1.0.0 + "@chromatic-com/playwright": ^0.*.* || ^1.0.0 + peerDependenciesMeta: + "@chromatic-com/cypress": + optional: true + "@chromatic-com/playwright": + optional: true + bin: + chroma: dist/bin.js + chromatic: dist/bin.js + chromatic-cli: dist/bin.js + checksum: 6ce615e73fd713bb41e813c311dcbfd0c4427a3f48aa11e4108854a9de8157ef191a23dd4179ec5568ec612ea8dc60b026ed74f993a76e163cbb765980e9c075 + languageName: node + linkType: hard + "chrome-trace-event@npm:^1.0.2": version: 1.0.2 resolution: "chrome-trace-event@npm:1.0.2" @@ -23312,10 +25045,10 @@ __metadata: languageName: node linkType: hard -"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2": - version: 1.3.1 - resolution: "cjs-module-lexer@npm:1.3.1" - checksum: 75f20ac264a397ea5c63f9c2343a51ab878043666468f275e94862f7180ec1d764a400ec0c09085dcf0db3193c74a8b571519abd2bf4be0d2be510d1377c8d4b +"cjs-module-lexer@npm:^1.0.0, cjs-module-lexer@npm:^1.2.2, cjs-module-lexer@npm:^1.2.3": + version: 1.4.1 + resolution: "cjs-module-lexer@npm:1.4.1" + checksum: 2556807a99aec1f9daac60741af96cd613a707f343174ae7967da46402c91dced411bf830d209f2e93be4cecea46fc75cecf1f17c799d7d8a9e1dd6204bfcd22 languageName: node linkType: hard @@ -23562,10 +25295,10 @@ __metadata: languageName: node linkType: hard -"cluster-key-slot@npm:^1.1.0": - version: 1.1.0 - resolution: "cluster-key-slot@npm:1.1.0" - checksum: fc953c75209b1ef9088081bab4e40a0b2586491c974ab93460569c014515ca5a2e31c043f185285e177007162fc353d07836d98f570c171dbe055775430e495b +"cluster-key-slot@npm:1.1.2, cluster-key-slot@npm:^1.1.0": + version: 1.1.2 + resolution: "cluster-key-slot@npm:1.1.2" + checksum: be0ad2d262502adc998597e83f9ded1b80f827f0452127c5a37b22dfca36bab8edf393f7b25bb626006fb9fb2436106939ede6d2d6ecf4229b96a47f27edd681 languageName: node linkType: hard @@ -24026,6 +25759,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.8": + version: 0.1.8 + resolution: "confbox@npm:0.1.8" + checksum: 5c7718ab22cf9e35a31c21ef124156076ae8c9dc65e6463d54961caf5a1d529284485a0fdf83fd23b27329f3b75b0c8c07d2e36c699f5151a2efe903343f976a + languageName: node + linkType: hard + "configstore@npm:^5.0.1": version: 5.0.1 resolution: "configstore@npm:5.0.1" @@ -24504,17 +26244,6 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^5.1.0": - version: 5.1.0 - resolution: "cross-spawn@npm:5.1.0" - dependencies: - lru-cache: ^4.0.1 - shebang-command: ^1.2.0 - which: ^1.2.9 - checksum: 726939c9954fc70c20e538923feaaa33bebc253247d13021737c3c7f68cdc3e0a57f720c0fe75057c0387995349f3f12e20e9bfdbf12274db28019c7ea4ec166 - languageName: node - linkType: hard - "cross-spawn@npm:^6.0.0": version: 6.0.5 resolution: "cross-spawn@npm:6.0.5" @@ -24528,14 +26257,14 @@ __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": - version: 7.0.5 - resolution: "cross-spawn@npm:7.0.5" +"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": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" dependencies: path-key: ^3.1.0 shebang-command: ^2.0.0 which: ^2.0.1 - checksum: 55c50004cb6bbea3649784caac6e7b8ddd03fa8c1e14dbd5a1f15896708378006eb7526a52a0f48770c768c9b8aed48a5888eb8e785ff59ff7749e74f66cd96b + checksum: 8d306efacaf6f3f60e0224c287664093fa9185680b2d195852ba9a863f85d02dcc737094c6e512175f8ee0161f9b87c73c6826034c2422e39de7d6569cf4503b languageName: node linkType: hard @@ -24610,9 +26339,9 @@ __metadata: languageName: node linkType: hard -"css-loader@npm:^7.0.0": - version: 7.1.2 - resolution: "css-loader@npm:7.1.2" +"css-loader@npm:^6.5.1, css-loader@npm:^6.7.1": + version: 6.11.0 + resolution: "css-loader@npm:6.11.0" dependencies: icss-utils: ^5.1.0 postcss: ^8.4.33 @@ -24624,13 +26353,13 @@ __metadata: semver: ^7.5.4 peerDependencies: "@rspack/core": 0.x || 1.x - webpack: ^5.27.0 + webpack: ^5.0.0 peerDependenciesMeta: "@rspack/core": optional: true webpack: optional: true - checksum: 15bfd90d778ddab90ee1d04c8c8bcc13ea6c0791d01b52b09d1b1c753b3410f7a7788a510d93726a9878e70b7c1a140f21efdf5c96e1857872107551d3897822 + checksum: 5c8d35975a7121334905394e88e28f05df72f037dbed2fb8fec4be5f0b313ae73a13894ba791867d4a4190c35896da84a7fd0c54fb426db55d85ba5e714edbe3 languageName: node linkType: hard @@ -24824,7 +26553,7 @@ __metadata: languageName: node linkType: hard -"csstype@npm:^3.0.2, csstype@npm:^3.1.2, csstype@npm:^3.1.3": +"csstype@npm:^3.0.2, csstype@npm:^3.0.7, csstype@npm:^3.1.2, csstype@npm:^3.1.3": version: 3.0.9 resolution: "csstype@npm:3.0.9" checksum: 199f9af7e673f9f188525c3102a329d637ff46c52f6385a4427ff5cb17adcb736189150170a7af7c5701d18d7704bdad130273f4aa7e44c6c4f9967e6115dc93 @@ -25034,9 +26763,9 @@ __metadata: linkType: hard "dataloader@npm:^2.0.0, dataloader@npm:^2.2.2": - version: 2.2.2 - resolution: "dataloader@npm:2.2.2" - checksum: 4dabd247089c29f194e94d5434d504f99156c5c214a03463c20f3f17f40398d7e179edee69a27c16e315519ac8739042a810090087ae26449a0e685156a02c65 + version: 2.2.3 + resolution: "dataloader@npm:2.2.3" + checksum: cc272181f6cad0ea20511c0a0d270cbc1df960a3526ab24941bbeb2cb7120499a598fe2cd41b4818527367acf7bc1be0723b6e5034637db4759a396c904b78a6 languageName: node linkType: hard @@ -25102,15 +26831,15 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:~4.3.6": - version: 4.3.7 - resolution: "debug@npm:4.3.7" +"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:~4.4.0": + version: 4.4.0 + resolution: "debug@npm:4.4.0" dependencies: ms: ^2.1.3 peerDependenciesMeta: supports-color: optional: true - checksum: 822d74e209cd910ef0802d261b150314bbcf36c582ccdbb3e70f0894823c17e49a50d3e66d96b633524263975ca16b6a833f3e3b7e030c157169a5fabac63160 + checksum: fb42df878dd0e22816fc56e1fdca9da73caa85212fbe40c868b1295a6878f9101ae684f4eeef516c13acfc700f5ea07f1136954f43d4cd2d477a811144136479 languageName: node linkType: hard @@ -25183,15 +26912,22 @@ __metadata: languageName: node linkType: hard -"dedent@npm:^1.0.0": - version: 1.5.1 - resolution: "dedent@npm:1.5.1" +"dedent@npm:^0.7.0": + version: 0.7.0 + resolution: "dedent@npm:0.7.0" + checksum: 87de191050d9a40dd70cad01159a0bcf05ecb59750951242070b6abf9569088684880d00ba92a955b4058804f16eeaf91d604f283929b4f614d181cd7ae633d2 + languageName: node + linkType: hard + +"dedent@npm:^1.0.0, dedent@npm:^1.5.3": + version: 1.5.3 + resolution: "dedent@npm:1.5.3" peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - checksum: c3c300a14edf1bdf5a873f9e4b22e839d62490bc5c8d6169c1f15858a1a76733d06a9a56930e963d677a2ceeca4b6b0894cc5ea2f501aa382ca5b92af3413c2a + checksum: 045b595557b2a8ea2eb9b0b4623d764e9a87326486fe2b61191b4342ed93dc01245644d8a09f3108a50c0ee7965f1eedd92e4a3a503ed89ea8e810566ea27f9a languageName: node linkType: hard @@ -25223,6 +26959,13 @@ __metadata: languageName: node linkType: hard +"deep-object-diff@npm:^1.1.9": + version: 1.1.9 + resolution: "deep-object-diff@npm:1.1.9" + checksum: ecd42455e4773f653595d28070295e7aaa8402db5f8ab21d0bec115a7cb4de5e207a5665514767da5f025c96597f1d3a0a4888aeb4dd49e03c996871a3aa05ef + languageName: node + linkType: hard + "deepmerge@npm:^4.2.2, deepmerge@npm:^4.3.1, deepmerge@npm:~4.3.0": version: 4.3.1 resolution: "deepmerge@npm:4.3.1" @@ -25396,7 +27139,7 @@ __metadata: languageName: node linkType: hard -"dequal@npm:^2.0.0, dequal@npm:^2.0.3": +"dequal@npm:^2.0.0, dequal@npm:^2.0.2, dequal@npm:^2.0.3": version: 2.0.3 resolution: "dequal@npm:2.0.3" checksum: 8679b850e1a3d0ebbc46ee780d5df7b478c23f335887464023a631d1b9af051ad4a6595a44220f9ff8ff95a8ddccf019b5ad778a976fd7bbf77383d36f412f90 @@ -25999,10 +27742,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.5.4": - version: 1.5.13 - resolution: "electron-to-chromium@npm:1.5.13" - checksum: f18ac84dd3bf9a200654a6a9292b9ec4bced0cf9bd26cec9941b775f4470c581c9d043e70b37a124d9752dcc0f47fc96613d52b2defd8e59632852730cb418b9 +"electron-to-chromium@npm:^1.5.41": + version: 1.5.65 + resolution: "electron-to-chromium@npm:1.5.65" + checksum: 4a112a038771c415f77e88fb3e3d929ceac4600b4612c55eb5d955a37c24842725f00c14f0f6838fd46edd832351c702b24c592c544d2e1e630d084f9df9f275 languageName: node linkType: hard @@ -26095,6 +27838,17 @@ __metadata: languageName: node linkType: hard +"endent@npm:^2.0.1": + version: 2.1.0 + resolution: "endent@npm:2.1.0" + dependencies: + dedent: ^0.7.0 + fast-json-parse: ^1.0.3 + objectorarray: ^1.0.5 + checksum: c352831088fce745a39ddbd5f87a17e073ea6556e7e96e9010d945a3f3020f836b9a84657123fa01e897db9216f4b080d950b5ded9bf3a8227f14a34efaaaf7c + languageName: node + linkType: hard + "enhanced-resolve@npm:^5.17.1": version: 5.17.1 resolution: "enhanced-resolve@npm:5.17.1" @@ -26166,12 +27920,12 @@ __metadata: languageName: node linkType: hard -"error-stack-parser@npm:^2.0.6": - version: 2.0.6 - resolution: "error-stack-parser@npm:2.0.6" +"error-stack-parser@npm:^2.0.6, error-stack-parser@npm:^2.1.4": + version: 2.1.4 + resolution: "error-stack-parser@npm:2.1.4" dependencies: - stackframe: ^1.1.1 - checksum: bd8e048fcb1c0c74ab201271fec3b39c097a7c24bdef1718828d053c0584da5d7ad845253b5e4773803ee8e7450b23b0920e60a3b60dd403c1568c843058cb12 + stackframe: ^1.3.4 + checksum: 3b916d2d14c6682f287c8bfa28e14672f47eafe832701080e420e7cdbaebb2c50293868256a95706ac2330fe078cf5664713158b49bc30d7a5f2ac229ded0e18 languageName: node linkType: hard @@ -26289,10 +28043,10 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^1.2.1, es-module-lexer@npm:^1.3.1": - version: 1.4.1 - resolution: "es-module-lexer@npm:1.4.1" - checksum: a11b5a256d4e8e9c7d94c2fd87415ccd1591617b6edd847e064503f8eaece2d25e2e9078a02c5ce3ed5e83bb748f5b4820efbe78072c8beb07ac619c2edec35d +"es-module-lexer@npm:^1.2.1, es-module-lexer@npm:^1.3.1, es-module-lexer@npm:^1.5.0": + version: 1.5.4 + resolution: "es-module-lexer@npm:1.5.4" + checksum: a0cf04fb92d052647ac7d818d1913b98d3d3d0f5b9d88f0eafb993436e4c3e2c958599db68839d57f2dfa281fdf0f60e18d448eb78fc292c33c0f25635b6854f languageName: node linkType: hard @@ -26402,87 +28156,18 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:^0.21.0, esbuild@npm:^0.21.3": - version: 0.21.5 - resolution: "esbuild@npm:0.21.5" +"esbuild-register@npm:^3.5.0": + version: 3.6.0 + resolution: "esbuild-register@npm:3.6.0" dependencies: - "@esbuild/aix-ppc64": 0.21.5 - "@esbuild/android-arm": 0.21.5 - "@esbuild/android-arm64": 0.21.5 - "@esbuild/android-x64": 0.21.5 - "@esbuild/darwin-arm64": 0.21.5 - "@esbuild/darwin-x64": 0.21.5 - "@esbuild/freebsd-arm64": 0.21.5 - "@esbuild/freebsd-x64": 0.21.5 - "@esbuild/linux-arm": 0.21.5 - "@esbuild/linux-arm64": 0.21.5 - "@esbuild/linux-ia32": 0.21.5 - "@esbuild/linux-loong64": 0.21.5 - "@esbuild/linux-mips64el": 0.21.5 - "@esbuild/linux-ppc64": 0.21.5 - "@esbuild/linux-riscv64": 0.21.5 - "@esbuild/linux-s390x": 0.21.5 - "@esbuild/linux-x64": 0.21.5 - "@esbuild/netbsd-x64": 0.21.5 - "@esbuild/openbsd-x64": 0.21.5 - "@esbuild/sunos-x64": 0.21.5 - "@esbuild/win32-arm64": 0.21.5 - "@esbuild/win32-ia32": 0.21.5 - "@esbuild/win32-x64": 0.21.5 - dependenciesMeta: - "@esbuild/aix-ppc64": - optional: true - "@esbuild/android-arm": - optional: true - "@esbuild/android-arm64": - optional: true - "@esbuild/android-x64": - optional: true - "@esbuild/darwin-arm64": - optional: true - "@esbuild/darwin-x64": - optional: true - "@esbuild/freebsd-arm64": - optional: true - "@esbuild/freebsd-x64": - optional: true - "@esbuild/linux-arm": - optional: true - "@esbuild/linux-arm64": - optional: true - "@esbuild/linux-ia32": - optional: true - "@esbuild/linux-loong64": - optional: true - "@esbuild/linux-mips64el": - optional: true - "@esbuild/linux-ppc64": - optional: true - "@esbuild/linux-riscv64": - optional: true - "@esbuild/linux-s390x": - optional: true - "@esbuild/linux-x64": - optional: true - "@esbuild/netbsd-x64": - optional: true - "@esbuild/openbsd-x64": - optional: true - "@esbuild/sunos-x64": - optional: true - "@esbuild/win32-arm64": - optional: true - "@esbuild/win32-ia32": - optional: true - "@esbuild/win32-x64": - optional: true - bin: - esbuild: bin/esbuild - checksum: 2911c7b50b23a9df59a7d6d4cdd3a4f85855787f374dce751148dbb13305e0ce7e880dde1608c2ab7a927fc6cec3587b80995f7fc87a64b455f8b70b55fd8ec1 + debug: ^4.3.4 + peerDependencies: + esbuild: ">=0.12 <1" + checksum: 9221e26dde3366398a43183b600d8e9252b8003516cd766983a06c321eb07cf1b6b236948a21e4d1728c17a341c0fa52b49409c951d89fc7bf65d07d43c31a05 languageName: node linkType: hard -"esbuild@npm:^0.24.0": +"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0, esbuild@npm:^0.24.0": version: 0.24.0 resolution: "esbuild@npm:0.24.0" dependencies: @@ -26565,6 +28250,86 @@ __metadata: languageName: node linkType: hard +"esbuild@npm:^0.21.0, esbuild@npm:^0.21.3": + version: 0.21.5 + resolution: "esbuild@npm:0.21.5" + dependencies: + "@esbuild/aix-ppc64": 0.21.5 + "@esbuild/android-arm": 0.21.5 + "@esbuild/android-arm64": 0.21.5 + "@esbuild/android-x64": 0.21.5 + "@esbuild/darwin-arm64": 0.21.5 + "@esbuild/darwin-x64": 0.21.5 + "@esbuild/freebsd-arm64": 0.21.5 + "@esbuild/freebsd-x64": 0.21.5 + "@esbuild/linux-arm": 0.21.5 + "@esbuild/linux-arm64": 0.21.5 + "@esbuild/linux-ia32": 0.21.5 + "@esbuild/linux-loong64": 0.21.5 + "@esbuild/linux-mips64el": 0.21.5 + "@esbuild/linux-ppc64": 0.21.5 + "@esbuild/linux-riscv64": 0.21.5 + "@esbuild/linux-s390x": 0.21.5 + "@esbuild/linux-x64": 0.21.5 + "@esbuild/netbsd-x64": 0.21.5 + "@esbuild/openbsd-x64": 0.21.5 + "@esbuild/sunos-x64": 0.21.5 + "@esbuild/win32-arm64": 0.21.5 + "@esbuild/win32-ia32": 0.21.5 + "@esbuild/win32-x64": 0.21.5 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 2911c7b50b23a9df59a7d6d4cdd3a4f85855787f374dce751148dbb13305e0ce7e880dde1608c2ab7a927fc6cec3587b80995f7fc87a64b455f8b70b55fd8ec1 + languageName: node + linkType: hard + "esbuild@npm:esbuild-wasm@^0.15.15": version: 0.15.18 resolution: "esbuild-wasm@npm:0.15.18" @@ -26574,10 +28339,93 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1, escalade@npm:^3.1.2": - version: 3.1.2 - resolution: "escalade@npm:3.1.2" - checksum: 1ec0977aa2772075493002bdbd549d595ff6e9393b1cb0d7d6fcaf78c750da0c158f180938365486f75cb69fba20294351caddfce1b46552a7b6c3cde52eaa02 +"esbuild@npm:esbuild@>=0.17.6 <0.24.0": + version: 0.23.1 + resolution: "esbuild@npm:0.23.1" + dependencies: + "@esbuild/aix-ppc64": 0.23.1 + "@esbuild/android-arm": 0.23.1 + "@esbuild/android-arm64": 0.23.1 + "@esbuild/android-x64": 0.23.1 + "@esbuild/darwin-arm64": 0.23.1 + "@esbuild/darwin-x64": 0.23.1 + "@esbuild/freebsd-arm64": 0.23.1 + "@esbuild/freebsd-x64": 0.23.1 + "@esbuild/linux-arm": 0.23.1 + "@esbuild/linux-arm64": 0.23.1 + "@esbuild/linux-ia32": 0.23.1 + "@esbuild/linux-loong64": 0.23.1 + "@esbuild/linux-mips64el": 0.23.1 + "@esbuild/linux-ppc64": 0.23.1 + "@esbuild/linux-riscv64": 0.23.1 + "@esbuild/linux-s390x": 0.23.1 + "@esbuild/linux-x64": 0.23.1 + "@esbuild/netbsd-x64": 0.23.1 + "@esbuild/openbsd-arm64": 0.23.1 + "@esbuild/openbsd-x64": 0.23.1 + "@esbuild/sunos-x64": 0.23.1 + "@esbuild/win32-arm64": 0.23.1 + "@esbuild/win32-ia32": 0.23.1 + "@esbuild/win32-x64": 0.23.1 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 0413c3b9257327fb598427688b7186ea335bf1693746fe5713cc93c95854d6388b8ed4ad643fddf5b5ace093f7dcd9038dd58e087bf2da1f04dfb4c5571660af + languageName: node + linkType: hard + +"escalade@npm:^3.1.1, escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 47b029c83de01b0d17ad99ed766347b974b0d628e848de404018f3abee728e987da0d2d370ad4574aa3d5b5bfc368754fd085d69a30f8e75903486ec4b5b709e languageName: node linkType: hard @@ -26843,14 +28691,27 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-storybook@npm:^0.11.1": + version: 0.11.1 + resolution: "eslint-plugin-storybook@npm:0.11.1" + dependencies: + "@storybook/csf": ^0.1.11 + "@typescript-eslint/utils": ^8.8.1 + ts-dedent: ^2.2.0 + peerDependencies: + eslint: ">=6" + checksum: 8b8eb30b598f3c44c2bbf921e318215338f1159c1fba2d2f6cd5bc0b2ec14515655cf1760b5e11355baddabc2ac8446d4dc18ee6df6d2252555b126ff649a421 + languageName: node + linkType: hard + "eslint-plugin-testing-library@npm:^6.0.0": - version: 6.4.0 - resolution: "eslint-plugin-testing-library@npm:6.4.0" + version: 6.5.0 + resolution: "eslint-plugin-testing-library@npm:6.5.0" dependencies: "@typescript-eslint/utils": ^5.62.0 peerDependencies: eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 - checksum: cfaaf0582375efb15821d3bcc2d571ffcb7d23c4f66677b9fc921cf853ec0b2a38bae9e31b566db2c55952444ad8064ef2996ca82a3312bc7e2d79537be56b19 + checksum: 1ac544314b448541a3a3ecf73b21341e0a8b7b0566f3966f22e3de16de67d5ae830c43f5ccbf0d3ed5ffdaaccd7215487da930d7d87fac35cb671a875bfe4051 languageName: node linkType: hard @@ -26903,6 +28764,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^4.2.0": + version: 4.2.0 + resolution: "eslint-visitor-keys@npm:4.2.0" + checksum: 779c604672b570bb4da84cef32f6abb085ac78379779c1122d7879eade8bb38ae715645324597cf23232d03cef06032c9844d25c73625bc282a5bfd30247e5b5 + languageName: node + linkType: hard + "eslint-webpack-plugin@npm:^4.0.0": version: 4.2.0 resolution: "eslint-webpack-plugin@npm:4.2.0" @@ -27063,6 +28931,15 @@ __metadata: languageName: node linkType: hard +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": ^1.0.0 + checksum: a65728d5727b71de172c5df323385755a16c0fdab8234dc756c3854cfee343261ddfbb72a809a5660fac8c75d960bb3e21aa898c2d7e9b19bb298482ca58a3af + languageName: node + linkType: hard + "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -27077,6 +28954,16 @@ __metadata: languageName: node linkType: hard +"eval@npm:0.1.8": + version: 0.1.8 + resolution: "eval@npm:0.1.8" + dependencies: + "@types/node": "*" + require-like: ">= 0.1.1" + checksum: d005567f394cfbe60948e34982e4637d2665030f9aa7dcac581ea6f9ec6eceb87133ed3dc0ae21764aa362485c242a731dbb6371f1f1a86807c58676431e9d1a + languageName: node + linkType: hard + "event-emitter@npm:^0.3.5": version: 0.3.5 resolution: "event-emitter@npm:0.3.5" @@ -27302,7 +29189,6 @@ __metadata: "@backstage/plugin-catalog-backend-module-scaffolder-entity-model": "workspace:^" "@backstage/plugin-catalog-backend-module-unprocessed": "workspace:^" "@backstage/plugin-catalog-node": "workspace:^" - "@backstage/plugin-devtools-backend": "workspace:^" "@backstage/plugin-events-backend": "workspace:^" "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-kubernetes-backend": "workspace:^" @@ -27383,7 +29269,7 @@ __metadata: "@backstage/plugin-search-backend-node": "workspace:^" "@backstage/plugin-signals-backend": "workspace:^" "@backstage/plugin-techdocs-backend": "workspace:^" - "@opentelemetry/auto-instrumentations-node": ^0.52.0 + "@opentelemetry/auto-instrumentations-node": ^0.54.0 "@opentelemetry/exporter-prometheus": ^0.54.0 "@opentelemetry/sdk-node": ^0.54.0 example-app: "link:../app" @@ -27576,8 +29462,8 @@ __metadata: linkType: hard "express@npm:^4.14.0, express@npm:^4.17.1, express@npm:^4.17.3, express@npm:^4.18.1, express@npm:^4.18.2, express@npm:^4.19.2": - version: 4.21.1 - resolution: "express@npm:4.21.1" + version: 4.21.2 + resolution: "express@npm:4.21.2" dependencies: accepts: ~1.3.8 array-flatten: 1.1.1 @@ -27598,7 +29484,7 @@ __metadata: methods: ~1.1.2 on-finished: 2.4.1 parseurl: ~1.3.3 - path-to-regexp: 0.1.10 + path-to-regexp: 0.1.12 proxy-addr: ~2.0.7 qs: 6.13.0 range-parser: ~1.2.1 @@ -27610,7 +29496,7 @@ __metadata: type-is: ~1.6.18 utils-merge: 1.0.1 vary: ~1.1.2 - checksum: 5ac2b26d8aeddda5564fc0907227d29c100f90c0ead2ead9d474dc5108e8fb306c2de2083c4e3ba326e0906466f2b73417dbac16961f4075ff9f03785fd940fe + checksum: 3aef1d355622732e20b8f3a7c112d4391d44e2131f4f449e1f273a309752a41abfad714e881f177645517cbe29b3ccdc10b35e7e25c13506114244a5b72f549d languageName: node linkType: hard @@ -27954,6 +29840,13 @@ __metadata: languageName: node linkType: hard +"filesize@npm:^10.0.12": + version: 10.1.6 + resolution: "filesize@npm:10.1.6" + checksum: a797a9d41c8f27a9ae334d23f99fc5d903eac5d03c82190dc163901205435b56626fe1260c779ba3e87a2a34d426f19ff264c3f7d956e00f2d3ac69760b52e33 + languageName: node + linkType: hard + "filesize@npm:^8.0.6": version: 8.0.6 resolution: "filesize@npm:8.0.6" @@ -28018,6 +29911,17 @@ __metadata: languageName: node linkType: hard +"find-cache-dir@npm:^3.3.1": + version: 3.3.2 + resolution: "find-cache-dir@npm:3.3.2" + dependencies: + commondir: ^1.0.1 + make-dir: ^3.0.2 + pkg-dir: ^4.1.0 + checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 + languageName: node + linkType: hard + "find-file-up@npm:^2.0.1": version: 2.0.1 resolution: "find-file-up@npm:2.0.1" @@ -28137,6 +30041,15 @@ __metadata: languageName: node linkType: hard +"flat@npm:^5.0.2": + version: 5.0.2 + resolution: "flat@npm:5.0.2" + bin: + flat: cli.js + checksum: 12a1536ac746db74881316a181499a78ef953632ddd28050b7a3a43c62ef5462e3357c8c29d76072bb635f147f7a9a1f0c02efef6b4be28f8db62ceb3d5c7f5d + languageName: node + linkType: hard + "flatstr@npm:^1.0.12": version: 1.0.12 resolution: "flatstr@npm:1.0.12" @@ -28144,10 +30057,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:3.3.1, flatted@npm:^3.1.0, flatted@npm:^3.2.7": - version: 3.3.1 - resolution: "flatted@npm:3.3.1" - checksum: 85ae7181650bb728c221e7644cbc9f4bf28bc556f2fc89bb21266962bdf0ce1029cc7acc44bb646cd469d9baac7c317f64e841c4c4c00516afa97320cdac7f94 +"flatted@npm:3.3.2, flatted@npm:^3.1.0, flatted@npm:^3.2.7": + version: 3.3.2 + resolution: "flatted@npm:3.3.2" + checksum: ac3c159742e01d0e860a861164bcfd35bb567ccbebb8a0dd041e61cf3c64a435b917dd1e7ed1c380c2ebca85735fb16644485ec33665bc6aafc3b316aa1eed44 languageName: node linkType: hard @@ -28251,6 +30164,29 @@ __metadata: languageName: node linkType: hard +"fork-ts-checker-webpack-plugin@npm:^8.0.0": + version: 8.0.0 + resolution: "fork-ts-checker-webpack-plugin@npm:8.0.0" + dependencies: + "@babel/code-frame": ^7.16.7 + chalk: ^4.1.2 + chokidar: ^3.5.3 + cosmiconfig: ^7.0.1 + deepmerge: ^4.2.2 + fs-extra: ^10.0.0 + memfs: ^3.4.1 + minimatch: ^3.0.4 + node-abort-controller: ^3.0.1 + schema-utils: ^3.1.1 + semver: ^7.3.5 + tapable: ^2.2.1 + peerDependencies: + typescript: ">3.6.0" + webpack: ^5.11.0 + checksum: aad4cbc5b802e6281a2700a379837697c93ad95288468f9595219d91d9c26674736d37852bb4c4341e9122f26181e9e05fc1a362e8d029fdd88e99de7816037b + languageName: node + linkType: hard + "fork-ts-checker-webpack-plugin@npm:^9.0.0": version: 9.0.2 resolution: "fork-ts-checker-webpack-plugin@npm:9.0.2" @@ -28610,15 +30546,16 @@ __metadata: languageName: node linkType: hard -"gaxios@npm:^6.0.0, gaxios@npm:^6.0.2, gaxios@npm:^6.1.1": - version: 6.3.0 - resolution: "gaxios@npm:6.3.0" +"gaxios@npm:^6.0.0, gaxios@npm:^6.0.2, gaxios@npm:^6.0.3, gaxios@npm:^6.1.1": + version: 6.7.1 + resolution: "gaxios@npm:6.7.1" dependencies: extend: ^3.0.2 https-proxy-agent: ^7.0.1 is-stream: ^2.0.0 node-fetch: ^2.6.9 - checksum: 4d4a8db32d833f8012435e2016cb0c919cac288e821bf81f877504e4284ef12b444cd903448e738c4031cd5219adf1e8d68e7df2b3dba774db9fde27f71109d4 + uuid: ^9.0.1 + checksum: ed5952655339918e0868c6f4e079d6e9e55b20a242ddb1be25076cdfb0dd1ca5a2cb233da7352baa972c19f898a78fa6ba67e7d848717c9ca9877c269b5b02f7 languageName: node linkType: hard @@ -28650,6 +30587,13 @@ __metadata: languageName: node linkType: hard +"generic-pool@npm:3.9.0": + version: 3.9.0 + resolution: "generic-pool@npm:3.9.0" + checksum: 3d89e9b2018d2e3bbf44fec78c76b2b7d56d6a484237aa9daf6ff6eedb14b0899dadd703b5d810219baab2eb28e5128fb18b29e91e602deb2eccac14492d8ca8 + languageName: node + linkType: hard + "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" @@ -28744,6 +30688,16 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^9.0.1": + version: 9.0.1 + resolution: "get-stream@npm:9.0.1" + dependencies: + "@sec-ant/readable-stream": ^0.4.1 + is-stream: ^4.0.1 + checksum: 631df71d7bd60a7f373094d3c352e2ce412b82d30b1b0ec562e5a4aced976173a4cc0dabef019050e1aceaffb1f0e086349ab3d14377b0b7280510bd75bd3e1e + languageName: node + linkType: hard + "get-symbol-description@npm:^1.0.2": version: 1.0.2 resolution: "get-symbol-description@npm:1.0.2" @@ -29006,6 +30960,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:^15.11.0": + version: 15.12.0 + resolution: "globals@npm:15.12.0" + checksum: 2a134cc876dd73192489561e3c85be348dc1408fef043ebef605cdc437f64cd2fc922268db02e3348683d05d06bed10fb1c3653b3d4399a204a7ecd59e742a07 + languageName: node + linkType: hard + "globalthis@npm:^1.0.1, globalthis@npm:^1.0.3, globalthis@npm:^1.0.4": version: 1.0.4 resolution: "globalthis@npm:1.0.4" @@ -29037,19 +30998,6 @@ __metadata: languageName: node linkType: hard -"globby@npm:^13.1.2": - version: 13.1.3 - resolution: "globby@npm:13.1.3" - dependencies: - dir-glob: ^3.0.1 - fast-glob: ^3.2.11 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^4.0.0 - checksum: 93f06e02002cdf368f7e3d55bd59e7b00784c7cc8fe92c7ee5082cc7171ff6109fda45e1c97a80bb48bc811dedaf7843c7c9186f5f84bde4883ab630e13c43df - languageName: node - linkType: hard - "globby@npm:^14.0.2": version: 14.0.2 resolution: "globby@npm:14.0.2" @@ -29080,7 +31028,7 @@ __metadata: languageName: node linkType: hard -"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.3.0, google-auth-library@npm:^9.6.3": +"google-auth-library@npm:^9.0.0, google-auth-library@npm:^9.2.0, google-auth-library@npm:^9.3.0, google-auth-library@npm:^9.6.3, google-auth-library@npm:^9.7.0": version: 9.15.0 resolution: "google-auth-library@npm:9.15.0" dependencies: @@ -29121,6 +31069,20 @@ __metadata: languageName: node linkType: hard +"googleapis-common@npm:^7.0.0": + version: 7.2.0 + resolution: "googleapis-common@npm:7.2.0" + dependencies: + extend: ^3.0.2 + gaxios: ^6.0.3 + google-auth-library: ^9.7.0 + qs: ^6.7.0 + url-template: ^2.0.8 + uuid: ^9.0.0 + checksum: 58f520134c9d6f439ef81919471689f0278ef0ffdbd50c693a59282d95141be74df3a5614c25347c140fc44201e0ef998300389f4cbf51502f2351e67c758ab6 + languageName: node + linkType: hard + "gopd@npm:^1.0.1": version: 1.0.1 resolution: "gopd@npm:1.0.1" @@ -29717,7 +31679,7 @@ __metadata: languageName: node linkType: hard -"html-webpack-plugin@npm:^5.3.1": +"html-webpack-plugin@npm:^5.5.0, html-webpack-plugin@npm:^5.6.3": version: 5.6.3 resolution: "html-webpack-plugin@npm:5.6.3" dependencies: @@ -30019,11 +31981,11 @@ __metadata: linkType: hard "husky@npm:^9.0.0": - version: 9.1.6 - resolution: "husky@npm:9.1.6" + version: 9.1.7 + resolution: "husky@npm:9.1.7" bin: husky: bin.js - checksum: 421ccd8850378231aaefd70dbe9e4f1549b84ffe3a6897f93a202242bbc04e48bd498169aef43849411105d9fcf7c192b757d42661e28d06b934a609a4eb8771 + checksum: c2412753f15695db369634ba70f50f5c0b7e5cb13b673d0826c411ec1bd9ddef08c1dad89ea154f57da2521d2605bd64308af748749b27d08c5f563bcd89975f languageName: node linkType: hard @@ -31061,6 +33023,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^4.0.1": + version: 4.0.1 + resolution: "is-stream@npm:4.0.1" + checksum: cbea3f1fc271b21ceb228819d0c12a0965a02b57f39423925f99530b4eb86935235f258f06310b67cd02b2d10b49e9a0998f5ececf110ab7d3760bae4055ad23 + languageName: node + linkType: hard + "is-string@npm:^1.0.5, is-string@npm:^1.0.7": version: 1.0.7 resolution: "is-string@npm:1.0.7" @@ -31233,12 +33202,12 @@ __metadata: linkType: hard "isolated-vm@npm:^5.0.1": - version: 5.0.1 - resolution: "isolated-vm@npm:5.0.1" + version: 5.0.2 + resolution: "isolated-vm@npm:5.0.2" dependencies: node-gyp: latest - prebuild-install: ^7.1.1 - checksum: 33ca559797d8c20571015733309b313f55df667cbaf17f7c6445b707fcdfd8bef6896264a30e48eaaa5635ab1d33e826b4aa95a1ba0bf8d26b045a1226956956 + prebuild-install: ^7.1.2 + checksum: 065f19ecb2e43393e6833321105bfa5911d82d0165e25beeb779bb6a262e1401dd387c900bcc3ad706eb7e73f5c5d57ca16ef7e2ee710e62e86b2a5ef39ce76b languageName: node linkType: hard @@ -31263,8 +33232,8 @@ __metadata: linkType: hard "isomorphic-git@npm:^1.23.0": - version: 1.27.1 - resolution: "isomorphic-git@npm:1.27.1" + version: 1.27.2 + resolution: "isomorphic-git@npm:1.27.2" dependencies: async-lock: ^1.4.1 clean-git-ref: ^2.0.1 @@ -31273,13 +33242,14 @@ __metadata: ignore: ^5.1.4 minimisted: ^2.0.0 pako: ^1.0.10 + path-browserify: ^1.0.1 pify: ^4.0.1 readable-stream: ^3.4.0 sha.js: ^2.4.9 simple-get: ^4.0.1 bin: isogit: cli.cjs - checksum: ba6f3c10b3160dac74185881f1da1c5a9b6cbd32d5f273ebce7291055566e5c58f466f89be9039e9c83ededd86a69e367bc4050262bbfbc6b785eea211a7f923 + checksum: 93077ba9192a67a9c2ebc3d4d00d7647cc6a20c546bd2c4fce6716cc5c2ce7772eb16b5493ab77fe3331eddb8b43d6f58855293a1dd5536130e7c6a60d9d4125 languageName: node linkType: hard @@ -31441,6 +33411,13 @@ __metadata: languageName: node linkType: hard +"javascript-stringify@npm:^2.0.1": + version: 2.1.0 + resolution: "javascript-stringify@npm:2.1.0" + checksum: 009981ec84299da88795fc764221ed213e3d52251cc93a396430a7a02ae09f1163a9be36a36808689681a8e6113cf00fe97ec2eea2552df48111f79be59e9358 + languageName: node + linkType: hard + "jest-changed-files@npm:^29.7.0": version: 29.7.0 resolution: "jest-changed-files@npm:29.7.0" @@ -31913,11 +33890,11 @@ __metadata: linkType: hard "jest-when@npm:^3.1.0": - version: 3.6.0 - resolution: "jest-when@npm:3.6.0" + version: 3.7.0 + resolution: "jest-when@npm:3.7.0" peerDependencies: jest: ">= 25" - checksum: ed32ed84e5802bb6fec98966cdf862ce59677551be33d3795e6ac7a6207acf467ed559573d671c8d94c59f7fc0780cf358d2d165d81cdc7d9611250d975ee024 + checksum: d805e2af8e76bf172e33dfde5280590fbc3510427a2d671d3a36df1c90c1bb68ebfee2ea4c87132e265973c7092d3ad20efb69398bd70141f7abef8815d5ad00 languageName: node linkType: hard @@ -32146,6 +34123,13 @@ __metadata: languageName: node linkType: hard +"jsdoc-type-pratt-parser@npm:^4.0.0": + version: 4.1.0 + resolution: "jsdoc-type-pratt-parser@npm:4.1.0" + checksum: e7642a508b090b1bdf17775383000ed71013c38e1231c1e576e5374636e8baf7c3fae8bf0252f5e1d3397d95efd56e8c8a5dd1a0de76d05d1499cbcb3c325bc3 + languageName: node + linkType: hard + "jsdom@npm:^20.0.0": version: 20.0.0 resolution: "jsdom@npm:20.0.0" @@ -32220,19 +34204,19 @@ __metadata: languageName: node linkType: hard -"jsep@npm:^1.2.0, jsep@npm:^1.3.6, jsep@npm:^1.3.9": +"jsep@npm:^1.2.0, jsep@npm:^1.3.6, jsep@npm:^1.4.0": version: 1.4.0 resolution: "jsep@npm:1.4.0" checksum: 8e7af5ecb91483b227092b87a3e85b5df3e848dbe6f201b19efcb18047567530d21dfeecb0978e09d1f66554fcfaed84176819eeacdfc86f61dc05c40c18f824 languageName: node linkType: hard -"jsesc@npm:^2.5.1": - version: 2.5.2 - resolution: "jsesc@npm:2.5.2" +"jsesc@npm:^3.0.2": + version: 3.0.2 + resolution: "jsesc@npm:3.0.2" bin: jsesc: bin/jsesc - checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + checksum: a36d3ca40574a974d9c2063bf68c2b6141c20da8f2a36bd3279fc802563f35f0527a6c828801295bdfb2803952cf2cf387786c2c90ed564f88d5782475abfe3c languageName: node linkType: hard @@ -32410,7 +34394,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2, json5@npm:^2.1.3, json5@npm:^2.2.3": +"json5@npm:^2.1.2, json5@npm:^2.1.3, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -32445,7 +34429,7 @@ __metadata: languageName: node linkType: hard -"jsonfile@npm:^6.0.1": +"jsonfile@npm:^6.0.1, jsonfile@npm:^6.1.0": version: 6.1.0 resolution: "jsonfile@npm:6.1.0" dependencies: @@ -32472,17 +34456,17 @@ __metadata: languageName: node linkType: hard -"jsonpath-plus@npm:10.1.0, jsonpath-plus@npm:^10.0.0, jsonpath-plus@npm:^6.0.1 || ^10.1.0": - version: 10.1.0 - resolution: "jsonpath-plus@npm:10.1.0" +"jsonpath-plus@npm:10.2.0, jsonpath-plus@npm:^10.0.0, jsonpath-plus@npm:^6.0.1 || ^10.1.0": + version: 10.2.0 + resolution: "jsonpath-plus@npm:10.2.0" dependencies: - "@jsep-plugin/assignment": ^1.2.1 - "@jsep-plugin/regex": ^1.0.3 - jsep: ^1.3.9 + "@jsep-plugin/assignment": ^1.3.0 + "@jsep-plugin/regex": ^1.0.4 + jsep: ^1.4.0 bin: jsonpath: bin/jsonpath-cli.js jsonpath-plus: bin/jsonpath-cli.js - checksum: 9369a9466e3bb3eca064debe3fd87d9cf791b9c8a23be7c00902497cd8f9dd632290d471e3c7bb09da0aa92626204f9c9a27c429940802bc5046cc8c87f3c596 + checksum: 862a96a0179f342fa6c012065fa78458d4ae4835f18a6ef580d18807101d8c2c3509dc20c9857474503205bff8f06c309e17d7420b68196262d15ad1e4f22146 languageName: node linkType: hard @@ -32724,12 +34708,12 @@ __metadata: languageName: node linkType: hard -"keyv@npm:*, keyv@npm:^4.0.0, keyv@npm:^4.5.2": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" +"keyv@npm:*, keyv@npm:^5.2.1": + version: 5.2.1 + resolution: "keyv@npm:5.2.1" dependencies: - json-buffer: 3.0.1 - checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 + "@keyv/serialize": "*" + checksum: 92f02ce8a61d3f832c72bc305a0a3408ab3ba322702175c8f23ddb7b317cdef6525fa084135ca4218f40afe17397f2b5b0f38fb1f0758fb47e8cd5d2699963d2 languageName: node linkType: hard @@ -32742,6 +34726,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^4.0.0, keyv@npm:^4.5.2": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: 3.0.1 + checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 + languageName: node + linkType: hard + "kind-of@npm:^6.0.2": version: 6.0.3 resolution: "kind-of@npm:6.0.3" @@ -32803,8 +34796,8 @@ __metadata: linkType: hard "knip@npm:^5.0.0": - version: 5.37.1 - resolution: "knip@npm:5.37.1" + version: 5.39.4 + resolution: "knip@npm:5.39.4" dependencies: "@nodelib/fs.walk": 1.2.8 "@snyk/github-codeowners": 1.1.0 @@ -32817,7 +34810,7 @@ __metadata: picocolors: ^1.1.0 picomatch: ^4.0.1 pretty-ms: ^9.0.0 - smol-toml: ^1.3.0 + smol-toml: ^1.3.1 strip-json-comments: 5.0.1 summary: 2.1.0 zod: ^3.22.4 @@ -32828,7 +34821,7 @@ __metadata: bin: knip: bin/knip.js knip-bun: bin/knip-bun.js - checksum: 8b1d59d3fc488b49c681da5b35feb256a0e82bf4c609001ffd410b559d5d58fc36e7c3dbd3c78f26416d49750a8abd117cd77648cde929d46fda6d3de90f3629 + checksum: 0a67865d11e015e324097616caec95f2bec15081daf1a969efcabd0f183020a6c6460326d2ea8cfc1c60b3ecf285710420c328c3ff4093018aec1d077b5815d7 languageName: node linkType: hard @@ -32881,14 +34874,14 @@ __metadata: linkType: hard "kubernetes-models@npm:^4.1.0, kubernetes-models@npm:^4.3.1": - version: 4.4.0 - resolution: "kubernetes-models@npm:4.4.0" + version: 4.4.2 + resolution: "kubernetes-models@npm:4.4.2" dependencies: - "@kubernetes-models/apimachinery": ^2.0.0 - "@kubernetes-models/base": ^5.0.0 + "@kubernetes-models/apimachinery": ^2.0.2 + "@kubernetes-models/base": ^5.0.1 "@kubernetes-models/validate": ^4.0.0 "@swc/helpers": ^0.5.8 - checksum: 9884c56c35415fe4b44a676a8b628e91fab17eb9a5ef5de08b7b9652d74afeb843d4a139d52bb19e1aaaeba44545542e92cef737b845a2cff5139aa62f820ced + checksum: 7c449f69cdda44b177e02185305489dbf492a264c8d71debac0d051831bef76936ed1ec6669fa2090ceb5a20ab9a82b4698d72cac6447c636fdeb6c1960bba9c languageName: node linkType: hard @@ -33050,10 +35043,10 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:~3.1.2": - version: 3.1.2 - resolution: "lilconfig@npm:3.1.2" - checksum: 4e8b83ddd1d0ad722600994e6ba5d858ddca14f0587aa6b9c8185e17548149b5e13d4d583d811e9e9323157fa8c6a527e827739794c7502b59243c58e210b8c3 +"lilconfig@npm:~3.1.3": + version: 3.1.3 + resolution: "lilconfig@npm:3.1.3" + checksum: 644eb10830350f9cdc88610f71a921f510574ed02424b57b0b3abb66ea725d7a082559552524a842f4e0272c196b88dfe1ff7d35ffcc6f45736777185cd67c9a languageName: node linkType: hard @@ -33100,22 +35093,22 @@ __metadata: linkType: hard "lint-staged@npm:^15.0.0": - version: 15.2.10 - resolution: "lint-staged@npm:15.2.10" + version: 15.2.11 + resolution: "lint-staged@npm:15.2.11" dependencies: chalk: ~5.3.0 commander: ~12.1.0 - debug: ~4.3.6 + debug: ~4.4.0 execa: ~8.0.1 - lilconfig: ~3.1.2 - listr2: ~8.2.4 + lilconfig: ~3.1.3 + listr2: ~8.2.5 micromatch: ~4.0.8 pidtree: ~0.6.0 string-argv: ~0.3.2 - yaml: ~2.5.0 + yaml: ~2.6.1 bin: lint-staged: bin/lint-staged.js - checksum: 7ab255b848478ca47c6b94aad0e7a3cfe5ba48ae1fb353cfa86635741333b83b1fd793d7cac6d44bf0388ad087d7e0250c7ec0a8ebece63fbcf7a8d175279809 + checksum: 9668e67791fd73aa91cf9268641a5b41191b4221ac9e4d34b51bb10088a082548aa5984d9b38066c3832e41f5a01bbb36aa41d9a8c96bbc775301cb5c9071e13 languageName: node linkType: hard @@ -33126,9 +35119,9 @@ __metadata: languageName: node linkType: hard -"listr2@npm:~8.2.4": - version: 8.2.4 - resolution: "listr2@npm:8.2.4" +"listr2@npm:~8.2.5": + version: 8.2.5 + resolution: "listr2@npm:8.2.5" dependencies: cli-truncate: ^4.0.0 colorette: ^2.0.20 @@ -33136,7 +35129,7 @@ __metadata: log-update: ^6.1.0 rfdc: ^1.4.1 wrap-ansi: ^9.0.0 - checksum: b1cdcae653ff967a9b28637e346df2d6614165b4ad1e9e36b1403bc972550c51f57ec0e6d307dc3921ceea0601e244e848ab79457c6d570ab1f088b577a63d90 + checksum: 0ca2387b067eb11bbe91863f36903f3a5a040790422a499cc1a15806d8497979e7d1990bd129061c0510906b2971eaa97a74a9635e3ec5abd5830c9749b655b9 languageName: node linkType: hard @@ -33557,7 +35550,7 @@ __metadata: languageName: node linkType: hard -"loupe@npm:^3.1.0, loupe@npm:^3.1.1": +"loupe@npm:^3.1.0, loupe@npm:^3.1.1, loupe@npm:^3.1.2": version: 3.1.2 resolution: "loupe@npm:3.1.2" checksum: 4a75bbe8877a1ced3603e08b1095cd6f4c987c50fe63719fdc3009029560f91e07a915e7f6eff1322bb62bfb2a2beeef06b13ccb3c12f81bda9f3674434dcab9 @@ -33587,6 +35580,13 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^3.0.0": + version: 3.0.0 + resolution: "lowercase-keys@npm:3.0.0" + checksum: 67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5 + languageName: node + linkType: hard + "lowlight@npm:^1.17.0": version: 1.20.0 resolution: "lowlight@npm:1.20.0" @@ -33597,23 +35597,13 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.0.0, lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": +"lru-cache@npm:^10.0.0, lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0, lru-cache@npm:^10.4.3": version: 10.4.3 resolution: "lru-cache@npm:10.4.3" checksum: 6476138d2125387a6d20f100608c2583d415a4f64a0fecf30c9e2dda976614f09cad4baa0842447bd37dd459a7bd27f57d9d8f8ce558805abd487c583f3d774a languageName: node linkType: hard -"lru-cache@npm:^4.0.1": - version: 4.1.5 - resolution: "lru-cache@npm:4.1.5" - dependencies: - pseudomap: ^1.0.2 - yallist: ^2.1.2 - checksum: 4bb4b58a36cd7dc4dcec74cbe6a8f766a38b7426f1ff59d4cf7d82a2aa9b9565cd1cb98f6ff60ce5cd174524868d7bc9b7b1c294371851356066ca9ac4cf135a - languageName: node - linkType: hard - "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -33694,12 +35684,12 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.10, magic-string@npm:^0.30.3": - version: 0.30.10 - resolution: "magic-string@npm:0.30.10" +"magic-string@npm:^0.30.10, magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": + version: 0.30.14 + resolution: "magic-string@npm:0.30.14" dependencies: - "@jridgewell/sourcemap-codec": ^1.4.15 - checksum: 456fd47c39b296c47dff967e1965121ace35417eab7f45a99e681e725b8661b48e1573c366ee67a27715025b3740773c46b088f115421c7365ea4ea6fa10d399 + "@jridgewell/sourcemap-codec": ^1.5.0 + checksum: 67b3b2d817a7c4e94cb63e2dcaffbeee3b76ff0798eeaee8159a6ff4faee30db824375b2cadbf43807b56c6802fe6373b40d02567d489593017012d74ec0b719 languageName: node linkType: hard @@ -33713,7 +35703,7 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.0": +"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: @@ -33772,6 +35762,25 @@ __metadata: languageName: node linkType: hard +"make-fetch-happen@npm:^14.0.3": + version: 14.0.3 + resolution: "make-fetch-happen@npm:14.0.3" + dependencies: + "@npmcli/agent": ^3.0.0 + cacache: ^19.0.1 + http-cache-semantics: ^4.1.1 + minipass: ^7.0.2 + minipass-fetch: ^4.0.0 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^1.0.0 + proc-log: ^5.0.0 + promise-retry: ^2.0.1 + ssri: ^12.0.0 + checksum: 6fb2fee6da3d98f1953b03d315826b5c5a4ea1f908481afc113782d8027e19f080c85ae998454de4e5f27a681d3ec58d57278f0868d4e0b736f51d396b661691 + languageName: node + linkType: hard + "make-fetch-happen@npm:^9.1.0": version: 9.1.0 resolution: "make-fetch-happen@npm:9.1.0" @@ -33814,6 +35823,13 @@ __metadata: languageName: node linkType: hard +"map-or-similar@npm:^1.5.0": + version: 1.5.0 + resolution: "map-or-similar@npm:1.5.0" + checksum: f65c0d420e272d0fce4e24db35f6a08109218480bca1d61eaa442cbe6cf46270b840218d3b5e94e4bfcc2595f1d0a1fa5885df750b52aac9ab1d437b29dcce38 + languageName: node + linkType: hard + "markdown-escape@npm:^2.0.0": version: 2.0.0 resolution: "markdown-escape@npm:2.0.0" @@ -34092,6 +36108,15 @@ __metadata: languageName: node linkType: hard +"media-query-parser@npm:^2.0.2": + version: 2.0.2 + resolution: "media-query-parser@npm:2.0.2" + dependencies: + "@babel/runtime": ^7.12.5 + checksum: 8ef956d9e63fe6f4041988beda69843b3a6bb48228ea2923a066f6e7c8f7c5dba75fae357318c48a97ed5beae840b8425cb7e727fc1bb77acc65f2005f8945ab + languageName: node + linkType: hard + "media-typer@npm:0.3.0": version: 0.3.0 resolution: "media-typer@npm:0.3.0" @@ -34141,7 +36166,7 @@ __metadata: languageName: node linkType: hard -"memfs@npm:^3.1.2, memfs@npm:^3.4.1": +"memfs@npm:^3.1.2, memfs@npm:^3.4.1, memfs@npm:^3.4.12": version: 3.5.3 resolution: "memfs@npm:3.5.3" dependencies: @@ -34159,10 +36184,10 @@ __metadata: languageName: node linkType: hard -"memjs@npm:^1.3.1": - version: 1.3.1 - resolution: "memjs@npm:1.3.1" - checksum: cb70879055151f15292e95ab57765e745c84d2fedd363b453afc3e2f48bf185e3771eecf9544f95009a3a374e810e34c1e18948134e814d791c2f0f35359ddeb +"memjs@npm:^1.3.1, memjs@npm:^1.3.2": + version: 1.3.2 + resolution: "memjs@npm:1.3.2" + checksum: f92c2a43725b70af69832f807d02b87a07609a1c1f2c8c37670dff5bae6ac5f0d767cc8b3a6a59626703538f96c0bd4f03f9d00ea3b28aeb33270d24e8782233 languageName: node linkType: hard @@ -34189,6 +36214,15 @@ __metadata: languageName: node linkType: hard +"memoizerific@npm:^1.11.3": + version: 1.11.3 + resolution: "memoizerific@npm:1.11.3" + dependencies: + map-or-similar: ^1.5.0 + checksum: d51bdc3ed8c39b4b73845c90eb62d243ddf21899914352d0c303f5e1d477abcb192f4c605e008caa4a31d823225eeb22a99ba5ee825fb88d0c33382db3aee95a + languageName: node + linkType: hard + "merge-descriptors@npm:1.0.3, merge-descriptors@npm:^1.0.1": version: 1.0.3 resolution: "merge-descriptors@npm:1.0.3" @@ -34689,14 +36723,21 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.0": +"mimic-response@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-response@npm:4.0.0" + checksum: 33b804cc961efe206efdb1fca6a22540decdcfce6c14eb5c0c50e5ae9022267ab22ce8f5568b1f7247ba67500fe20d523d81e0e9f009b321ccd9d472e78d1850 + languageName: node + linkType: hard + +"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" checksum: bfc6dd03c5eaf623a4963ebd94d087f6f4bbbfd8c41329a7f09706b0cb66969c4ddd336abeb587bc44bc6f08e13bf90f0b374f9d71f9f01e04adc2cd6f083ef1 languageName: node linkType: hard -"mini-css-extract-plugin@npm:^2.4.2": +"mini-css-extract-plugin@npm:^2.4.2, mini-css-extract-plugin@npm:^2.9.2": version: 2.9.2 resolution: "mini-css-extract-plugin@npm:2.9.2" dependencies: @@ -34819,6 +36860,15 @@ __metadata: languageName: node linkType: hard +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 + languageName: node + linkType: hard + "minipass-fetch@npm:^1.3.2, minipass-fetch@npm:^1.4.1": version: 1.4.1 resolution: "minipass-fetch@npm:1.4.1" @@ -34864,6 +36914,21 @@ __metadata: languageName: node linkType: hard +"minipass-fetch@npm:^4.0.0": + version: 4.0.0 + resolution: "minipass-fetch@npm:4.0.0" + dependencies: + encoding: ^0.1.13 + minipass: ^7.0.3 + minipass-sized: ^1.0.3 + minizlib: ^3.0.1 + dependenciesMeta: + encoding: + optional: true + checksum: 7d59a31011ab9e4d1af6562dd4c4440e425b2baf4c5edbdd2e22fb25a88629e1cdceca39953ff209da504a46021df520f18fd9a519f36efae4750ff724ddadea + languageName: node + linkType: hard + "minipass-flush@npm:^1.0.5": version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" @@ -34998,6 +37063,18 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^1.4.2, mlly@npm:^1.7.2": + version: 1.7.3 + resolution: "mlly@npm:1.7.3" + dependencies: + acorn: ^8.14.0 + pathe: ^1.1.2 + pkg-types: ^1.2.1 + ufo: ^1.5.4 + checksum: 60d309c7ce2ac162224a087fcd683a891260511f57011b2f436b54dfef146b8aae7473013958a58d5b6039f2a8692c32a2599c8390c5b307d1119ad0d917b414 + languageName: node + linkType: hard + "mock-socket@npm:^9.3.0": version: 9.3.1 resolution: "mock-socket@npm:9.3.1" @@ -35055,8 +37132,8 @@ __metadata: linkType: hard "mockttp@npm:^3.13.0": - version: 3.15.4 - resolution: "mockttp@npm:3.15.4" + version: 3.15.5 + resolution: "mockttp@npm:3.15.5" dependencies: "@graphql-tools/schema": ^8.5.0 "@graphql-tools/utils": ^8.8.0 @@ -35102,7 +37179,14 @@ __metadata: ws: ^8.8.0 bin: mockttp: dist/admin/admin-bin.js - checksum: a143a05ea77e674f0c813d32e4ee7a3875fce94861852142d9cd83d4d446ea6bdb0e7754bc4939409fd6fe659d267e55daf9be8c97149c5b5d15cac8c9c5247d + checksum: 410d8b39cddb7975aeb2289a1735d8d65b28bf032e8b0e8990ce78ddbaa4c7c96108c54714a36a745b4784cf2bf129ddafa93a5458deacce2ca56a4adfd524e9 + languageName: node + linkType: hard + +"modern-ahocorasick@npm:^1.0.0": + version: 1.1.0 + resolution: "modern-ahocorasick@npm:1.1.0" + checksum: 78b99840c9af086c1e36a594ee85bebd8c19d48e2ef31a67d1bad0e673ac12fc931e5961abb5b16daaf820af4923e700f76b1793b7413e18782230162866a0af languageName: node linkType: hard @@ -35203,14 +37287,14 @@ __metadata: linkType: hard "msw@npm:^2.0.0, msw@npm:^2.0.8": - version: 2.6.4 - resolution: "msw@npm:2.6.4" + version: 2.6.9 + resolution: "msw@npm:2.6.9" dependencies: "@bundled-es-modules/cookie": ^2.0.1 "@bundled-es-modules/statuses": ^1.0.1 "@bundled-es-modules/tough-cookie": ^0.1.6 "@inquirer/confirm": ^5.0.0 - "@mswjs/interceptors": ^0.36.5 + "@mswjs/interceptors": ^0.37.0 "@open-draft/deferred-promise": ^2.2.0 "@open-draft/until": ^2.1.0 "@types/cookie": ^0.6.0 @@ -35231,7 +37315,7 @@ __metadata: optional: true bin: msw: cli/index.js - checksum: b53b0a8746b735220b8111284c5345baadd78b858c1119472635b5b59323e8246891947aaac30c9f5eb4c1fa5ccd5f2b77baedce21db36619cd90ee4ab7011f0 + checksum: 959d42bbc164fd6a2458398c0aa91d3ff605ec7492884ec6b39c2e72dd4064dc0d7d1083656cc676048d57d8d69348c8cb97952459b8157021269404ceee542b languageName: node linkType: hard @@ -35290,8 +37374,8 @@ __metadata: linkType: hard "mysql2@npm:^3.0.0": - version: 3.11.4 - resolution: "mysql2@npm:3.11.4" + version: 3.11.5 + resolution: "mysql2@npm:3.11.5" dependencies: aws-ssl-profiles: ^1.1.1 denque: ^2.1.0 @@ -35302,7 +37386,7 @@ __metadata: named-placeholders: ^1.1.3 seq-queue: ^0.0.5 sqlstring: ^2.3.2 - checksum: b4415028fad374b5bd5303968c28fc95feee60c1c946ef47f3581e0303c0e5978a306f44d6f665e3fdada5d6a0dd6c55515427a195700b90943d188f6db2f7ed + checksum: 19b184b5b9aafb5d0fd8a8e37f74f20b13631ad888669d6e563060f77b0293fdc80e72459b4090dbbb6307327c243c03dfe5e3760fd5b896fc4fd8f89551bc06 languageName: node linkType: hard @@ -35430,6 +37514,13 @@ __metadata: languageName: node linkType: hard +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 20ebfe79b2d2e7cf9cbc8239a72662b584f71164096e6e8896c8325055497c96f6b80cd22c258e8a2f2aa382a787795ec3ee8b37b422a302c7d4381b0d5ecfbb + languageName: node + linkType: hard + "neo-async@npm:^2.5.0, neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" @@ -35593,9 +37684,9 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^10.0.0, node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" +"node-gyp@npm:^10.0.0": + version: 10.3.1 + resolution: "node-gyp@npm:10.3.1" dependencies: env-paths: ^2.2.0 exponential-backoff: ^3.1.1 @@ -35609,7 +37700,7 @@ __metadata: which: ^4.0.0 bin: node-gyp: bin/node-gyp.js - checksum: 0233759d8c19765f7fdc259a35eb046ad86c3d09e22f7384613ae2b89647dd27fcf833fdf5293d9335041e91f9b1c539494225959cdb312a5c8080b7534b926f + checksum: 91b0690ab504fe051ad66863226dc5ecac72b8471f85e8428e4d5ca3217d3a2adfffae48cd555e8d009a4164689fff558b88d2bc9bfd246452a3336ab308cf99 languageName: node linkType: hard @@ -35633,6 +37724,26 @@ __metadata: languageName: node linkType: hard +"node-gyp@npm:latest": + version: 11.0.0 + resolution: "node-gyp@npm:11.0.0" + dependencies: + env-paths: ^2.2.0 + exponential-backoff: ^3.1.1 + glob: ^10.3.10 + graceful-fs: ^4.2.6 + make-fetch-happen: ^14.0.3 + nopt: ^8.0.0 + proc-log: ^5.0.0 + semver: ^7.3.5 + tar: ^7.4.3 + which: ^5.0.0 + bin: + node-gyp: bin/node-gyp.js + checksum: d7d5055ccc88177f721c7cd4f8f9440c29a0eb40e7b79dba89ef882ec957975dfc1dcb8225e79ab32481a02016eb13bbc051a913ea88d482d3cbdf2131156af4 + languageName: node + linkType: hard + "node-html-markdown@npm:^1.3.0": version: 1.3.0 resolution: "node-html-markdown@npm:1.3.0" @@ -35708,8 +37819,8 @@ __metadata: linkType: hard "node-mocks-http@npm:^1.0.0": - version: 1.16.1 - resolution: "node-mocks-http@npm:1.16.1" + version: 1.16.2 + resolution: "node-mocks-http@npm:1.16.2" dependencies: accepts: ^1.3.7 content-disposition: ^0.5.3 @@ -35729,7 +37840,7 @@ __metadata: optional: true "@types/node": optional: true - checksum: 198030725eac236062eb3547a7d5cec2d6f2d44bf05efab0ea621e90f671d6966dca2873faaea9bcbb5dde92a222aff0610a01d453c2f76b0bc5dbdf4bd8057a + checksum: 9d148c49947e2161dbfd55204f07352f3fd976a41dfe355a97bd932cb8d4dbf584be4058fc78b121a9d83f0b86397e00a591e87afa9a1ecfb0335608ef1ace96 languageName: node linkType: hard @@ -35811,8 +37922,8 @@ __metadata: linkType: hard "nodemon@npm:^3.0.1": - version: 3.1.7 - resolution: "nodemon@npm:3.1.7" + version: 3.1.9 + resolution: "nodemon@npm:3.1.9" dependencies: chokidar: ^3.5.2 debug: ^4 @@ -35826,7 +37937,7 @@ __metadata: undefsafe: ^2.0.5 bin: nodemon: bin/nodemon.js - checksum: c500ac2feb278ddb187049ac8ede6423c1fb074cc3dabf74882568d5e93401293c10039e184a9d1bfc617c983ddb432437d396b421926914d04ebba671a7d8b8 + checksum: d045065dea08904f1356d18132538e71a61df12cb4e2852730310492943676d4789bedb28c343a5d85d5e07558bf47b73f000a8017409f0b7d522a3c1c42b2e5 languageName: node linkType: hard @@ -35852,6 +37963,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^8.0.0": + version: 8.0.0 + resolution: "nopt@npm:8.0.0" + dependencies: + abbrev: ^2.0.0 + bin: + nopt: bin/nopt.js + checksum: 2cfc65e7ee38af2e04aea98f054753b0230011c0eeca4ecf131bd7d25984cbbf6f214586e0ae5dfcc2e830bc0bffa5a7fb28ea8d0b306ffd4ae8ea2d814c1ab3 + languageName: node + linkType: hard + "nopt@npm:~1.0.10": version: 1.0.10 resolution: "nopt@npm:1.0.10" @@ -35893,6 +38015,13 @@ __metadata: languageName: node linkType: hard +"normalize-url@npm:^8.0.1": + version: 8.0.1 + resolution: "normalize-url@npm:8.0.1" + checksum: 43ea9ef0d6d135dd1556ab67aa4b74820f0d9d15aa504b59fa35647c729f1147dfce48d3ad504998fd1010f089cfb82c86c6d9126eb5c5bd2e9bd25f3a97749b + languageName: node + linkType: hard + "notistack@npm:^3.0.1": version: 3.0.1 resolution: "notistack@npm:3.0.1" @@ -36227,6 +38356,13 @@ __metadata: languageName: node linkType: hard +"objectorarray@npm:^1.0.5": + version: 1.0.5 + resolution: "objectorarray@npm:1.0.5" + checksum: 8fd776aa495d113e217837f4adc1d53e63f656498237094d25f84c3e2c038b34b71d6fd85c4b60c7ae5f558790e5042426a400fae3eac35f297e11be12643a78 + languageName: node + linkType: hard + "obuf@npm:^1.0.0, obuf@npm:^1.1.2, obuf@npm:~1.1.2": version: 1.1.2 resolution: "obuf@npm:1.1.2" @@ -36366,7 +38502,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^8.0.0, open@npm:^8.4.0": +"open@npm:^8.0.0, open@npm:^8.0.4, open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" dependencies: @@ -36455,14 +38591,14 @@ __metadata: linkType: hard "openid-client@npm:^5.2.1, openid-client@npm:^5.3.0, openid-client@npm:^5.4.3, openid-client@npm:^5.5.0, openid-client@npm:^5.6.5": - version: 5.7.0 - resolution: "openid-client@npm:5.7.0" + version: 5.7.1 + resolution: "openid-client@npm:5.7.1" dependencies: jose: ^4.15.9 lru-cache: ^6.0.0 object-hash: ^2.2.0 oidc-token-hash: ^5.0.3 - checksum: 63fc76918fc12f3d6e1456a0b170f417defccf6820acb4581ffc226cb8c9a18d50f76f0982d7a00cce2896c732eb2a6361ad6ea04b127b2603e56408b680ef9c + checksum: 497aad2c8a022cef112ade19ed88fba6c8ca0e79607ebe5efdcf75c4095d7924ca479085c1c94f689f6dbc9442c61aab3c2443eb347bcbc6ef51df68827c7c47 languageName: node linkType: hard @@ -36698,6 +38834,13 @@ __metadata: languageName: node linkType: hard +"p-throttle@npm:^5.1.0": + version: 5.1.0 + resolution: "p-throttle@npm:5.1.0" + checksum: c412429cbb759a0772a083200a556e5866d4a7cb5383a9cc85880f47f07f4b1787fc33d2c824ab659fff0fc4a34a56e1d0712e88808f0c0ae0ffbe93b54f46c1 + languageName: node + linkType: hard + "p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" @@ -37183,10 +39326,10 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:0.1.10": - version: 0.1.10 - resolution: "path-to-regexp@npm:0.1.10" - checksum: ab7a3b7a0b914476d44030340b0a65d69851af2a0f33427df1476100ccb87d409c39e2182837a96b98fb38c4ef2ba6b87bdad62bb70a2c153876b8061760583c +"path-to-regexp@npm:0.1.12": + version: 0.1.12 + resolution: "path-to-regexp@npm:0.1.12" + checksum: ab237858bee7b25ecd885189f175ab5b5161e7b712b360d44f5c4516b8d271da3e4bf7bf0a7b9153ecb04c7d90ce8ff5158614e1208819cf62bac2b08452722e languageName: node linkType: hard @@ -37232,6 +39375,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.1, pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: ec5f778d9790e7b9ffc3e4c1df39a5bb1ce94657a4e3ad830c1276491ca9d79f189f47609884671db173400256b005f4955f7952f52a2aeb5834ad5fb4faf134 + languageName: node + linkType: hard + "pathval@npm:^2.0.0": version: 2.0.0 resolution: "pathval@npm:2.0.0" @@ -37425,7 +39575,7 @@ __metadata: languageName: node linkType: hard -"picocolors@npm:^1.0.0, picocolors@npm:^1.0.1, picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": +"picocolors@npm:^1.0.0, picocolors@npm:^1.1.0, picocolors@npm:^1.1.1": version: 1.1.1 resolution: "picocolors@npm:1.1.1" checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 @@ -37548,7 +39698,7 @@ __metadata: languageName: node linkType: hard -"pkg-dir@npm:^4.2.0": +"pkg-dir@npm:^4.1.0, pkg-dir@npm:^4.2.0": version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" dependencies: @@ -37566,6 +39716,17 @@ __metadata: languageName: node linkType: hard +"pkg-types@npm:^1.2.1": + version: 1.2.1 + resolution: "pkg-types@npm:1.2.1" + dependencies: + confbox: ^0.1.8 + mlly: ^1.7.2 + pathe: ^1.1.2 + checksum: d2e3ad7aef36cc92b17403e61c04db521bf0beb175ccb4d432c284239f00ec32ff37feb072a260613e9ff727911cff1127a083fd52f91b9bec6b62970f385702 + languageName: node + linkType: hard + "pkg-up@npm:^3.1.0": version: 3.1.0 resolution: "pkg-up@npm:3.1.0" @@ -37589,27 +39750,27 @@ __metadata: languageName: node linkType: hard -"playwright-core@npm:1.48.2": - version: 1.48.2 - resolution: "playwright-core@npm:1.48.2" +"playwright-core@npm:1.49.1": + version: 1.49.1 + resolution: "playwright-core@npm:1.49.1" bin: playwright-core: cli.js - checksum: a73ecea379f13f757ec38299871256a130d4abec5688369969a6b1ef6104c67f731a27c9a503a988c3e5b1141048552a3ed8c4d061cb631ff2ebab606835c10a + checksum: a940f4b10ff1de033b4b8594b5104b02849a892d9adda0d42330a872cd3d8d287ffd2b01fc33f33ccd34f8904bb8ae8220b878b62e899f3d9bcd1b0945ab45c7 languageName: node linkType: hard -"playwright@npm:1.48.2": - version: 1.48.2 - resolution: "playwright@npm:1.48.2" +"playwright@npm:1.49.1": + version: 1.49.1 + resolution: "playwright@npm:1.49.1" dependencies: fsevents: 2.3.2 - playwright-core: 1.48.2 + playwright-core: 1.49.1 dependenciesMeta: fsevents: optional: true bin: playwright: cli.js - checksum: 69ffb28b5a94fc21a9bd3439feb363ffebb21c6b00e6d08ffc225787be49005d6b57072ebb043e78378252850f2b7712f8478e6685138a8e445d6fda94a31e28 + checksum: c136d42d625e32614f90e5228a165dc8be48c5bfb52aca9210c6ff04161a409dbe42fe5ae4f05a2653f6a1b836876a04d3b0f24bcbbc053d1509c1d605b7c8d5 languageName: node linkType: hard @@ -37620,6 +39781,15 @@ __metadata: languageName: node linkType: hard +"polished@npm:^4.2.2": + version: 4.3.1 + resolution: "polished@npm:4.3.1" + dependencies: + "@babel/runtime": ^7.17.8 + checksum: a6f863c23f1d2f3f5cda3427b5885c9fb9e83b036d681e24820b143c7df40d2685bebb01c0939767120a28e1183671ae17c93db82ac30b3c20942180bb153bc7 + languageName: node + linkType: hard + "pony-cause@npm:^1.1.1": version: 1.1.1 resolution: "pony-cause@npm:1.1.1" @@ -38182,9 +40352,9 @@ __metadata: languageName: node linkType: hard -"prebuild-install@npm:^7.1.1": - version: 7.1.1 - resolution: "prebuild-install@npm:7.1.1" +"prebuild-install@npm:^7.1.1, prebuild-install@npm:^7.1.2": + version: 7.1.2 + resolution: "prebuild-install@npm:7.1.2" dependencies: detect-libc: ^2.0.0 expand-template: ^2.0.3 @@ -38200,7 +40370,7 @@ __metadata: tunnel-agent: ^0.6.0 bin: prebuild-install: bin.js - checksum: dbf96d0146b6b5827fc8f67f72074d2e19c69628b9a7a0a17d0fad1bf37e9f06922896972e074197fc00a52eae912993e6ef5a0d471652f561df5cb516f3f467 + checksum: 543dadf8c60e004ae9529e6013ca0cbeac8ef38b5f5ba5518cb0b622fe7f8758b34e4b5cb1a791db3cdc9d2281766302df6088bd1a225f206925d6fee17d6c5c languageName: node linkType: hard @@ -38331,6 +40501,13 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^5.0.0": + version: 5.0.0 + resolution: "proc-log@npm:5.0.0" + checksum: c78b26ecef6d5cce4a7489a1e9923d7b4b1679028c8654aef0463b27f4a90b0946cd598f55799da602895c52feb085ec76381d007ab8dcceebd40b89c2f9dfe0 + languageName: node + linkType: hard + "process-nextick-args@npm:^2.0.0, process-nextick-args@npm:~2.0.0": version: 2.0.1 resolution: "process-nextick-args@npm:2.0.1" @@ -38475,7 +40652,7 @@ __metadata: languageName: node linkType: hard -"protobufjs@npm:^7.2.5, protobufjs@npm:^7.2.6, protobufjs@npm:^7.3.0, protobufjs@npm:^7.3.2": +"protobufjs@npm:^7.2.5, protobufjs@npm:^7.2.6, protobufjs@npm:^7.3.0, protobufjs@npm:^7.3.2, protobufjs@npm:^7.4.0": version: 7.4.0 resolution: "protobufjs@npm:7.4.0" dependencies: @@ -38535,13 +40712,6 @@ __metadata: languageName: node linkType: hard -"pseudomap@npm:^1.0.2": - version: 1.0.2 - resolution: "pseudomap@npm:1.0.2" - checksum: 856c0aae0ff2ad60881168334448e898ad7a0e45fe7386d114b150084254c01e200c957cf378378025df4e052c7890c5bd933939b0e0d2ecfcc1dc2f0b2991f5 - languageName: node - linkType: hard - "psl@npm:^1.1.28, psl@npm:^1.1.33": version: 1.8.0 resolution: "psl@npm:1.8.0" @@ -38631,7 +40801,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.13.0, qs@npm:^6.10.1, qs@npm:^6.10.3, qs@npm:^6.11.0, qs@npm:^6.11.2, qs@npm:^6.12.2, qs@npm:^6.9.4": +"qs@npm:6.13.0": version: 6.13.0 resolution: "qs@npm:6.13.0" dependencies: @@ -38640,6 +40810,15 @@ __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.7.0, qs@npm:^6.9.4": + version: 6.13.1 + resolution: "qs@npm:6.13.1" + dependencies: + side-channel: ^1.0.6 + checksum: 86c5059146955fab76624e95771031541328c171b1d63d48a7ac3b1fdffe262faf8bc5fcadc1684e6f3da3ec87a8dedc8c0009792aceb20c5e94dc34cf468bb9 + languageName: node + linkType: hard + "qs@npm:~6.5.2": version: 6.5.3 resolution: "qs@npm:6.5.3" @@ -38818,7 +40997,7 @@ __metadata: languageName: node linkType: hard -"rate-limiter-flexible@npm:^4.0.0, rate-limiter-flexible@npm:^4.0.1": +"rate-limiter-flexible@npm:^4.0.1": version: 4.0.1 resolution: "rate-limiter-flexible@npm:4.0.1" checksum: 88cb4ae4c6a94646eb4987f08ae203896fc340d84038e145958607ab711d9c703e47e55f177a4bf9bab4c637c73ee2254fffe2ec4e289d41389c8502194ca868 @@ -38928,6 +41107,17 @@ __metadata: languageName: node linkType: hard +"react-confetti@npm:^6.1.0": + version: 6.1.0 + resolution: "react-confetti@npm:6.1.0" + dependencies: + tween-functions: ^1.2.0 + peerDependencies: + react: ^16.3.0 || ^17.0.1 || ^18.0.0 + checksum: 24b6975df144d2bf09d8e1c95ddc49e547775f911efaa8d96b49e522659d931539e9d9e48cc0db3a01f3a671be7e3824e6e728db85096f5527db5d1c69ebb153 + languageName: node + linkType: hard + "react-copy-to-clipboard@npm:5.1.0, react-copy-to-clipboard@npm:^5.0.4": version: 5.1.0 resolution: "react-copy-to-clipboard@npm:5.1.0" @@ -38994,6 +41184,33 @@ __metadata: languageName: node linkType: hard +"react-docgen-typescript@npm:^2.2.2": + version: 2.2.2 + resolution: "react-docgen-typescript@npm:2.2.2" + peerDependencies: + typescript: ">= 4.3.x" + checksum: a9826459ea44e818f21402728dd47f5cae60bd936574cefd4f90ad101ff3eebacd67b6e017b793309734ce62c037aa3072dbc855d2b0e29bad1a38cbf5bac115 + languageName: node + linkType: hard + +"react-docgen@npm:^7.0.0": + version: 7.1.0 + resolution: "react-docgen@npm:7.1.0" + dependencies: + "@babel/core": ^7.18.9 + "@babel/traverse": ^7.18.9 + "@babel/types": ^7.18.9 + "@types/babel__core": ^7.18.0 + "@types/babel__traverse": ^7.18.0 + "@types/doctrine": ^0.0.9 + "@types/resolve": ^1.20.2 + doctrine: ^3.0.0 + resolve: ^1.22.1 + strip-indent: ^4.0.0 + checksum: dfdec82a4d695e8b1e31b77eef4ceac0f60e00f13725f0a18886d2737595531e58a54f4dde5db4657276d194597bd5e67a1792ca52eb42a59b67943105f24893 + languageName: node + linkType: hard + "react-dom@npm:^16.13.1": version: 16.14.0 resolution: "react-dom@npm:16.14.0" @@ -39008,7 +41225,7 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^18.0.2": +"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react-dom@npm:^18.0.2": version: 18.3.1 resolution: "react-dom@npm:18.3.1" dependencies: @@ -39053,6 +41270,17 @@ __metadata: languageName: node linkType: hard +"react-error-boundary@npm:^4.1.2": + version: 4.1.2 + resolution: "react-error-boundary@npm:4.1.2" + dependencies: + "@babel/runtime": ^7.12.5 + peerDependencies: + react: ">=16.13.1" + checksum: afe692f1bbbfb5998b49e1001d7682a3cbfdc623dca1318b408e738606f3450d925c28fbbfa5dc84d2cf285d17c2e7f079d59386a27da354dea9c902a935149b + languageName: node + linkType: hard + "react-error-overlay@npm:^6.0.11": version: 6.0.11 resolution: "react-error-overlay@npm:6.0.11" @@ -39593,7 +41821,7 @@ __metadata: languageName: node linkType: hard -"react@npm:^18.0.2": +"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react@npm:^18.0.2": version: 18.3.1 resolution: "react@npm:18.3.1" dependencies: @@ -39737,7 +41965,7 @@ __metadata: languageName: node linkType: hard -"recast@npm:^0.23.9": +"recast@npm:^0.23.5, recast@npm:^0.23.9": version: 0.23.9 resolution: "recast@npm:0.23.9" dependencies: @@ -39803,6 +42031,20 @@ __metadata: languageName: node linkType: hard +"redis@npm:^4.7.0": + version: 4.7.0 + resolution: "redis@npm:4.7.0" + dependencies: + "@redis/bloom": 1.2.0 + "@redis/client": 1.6.0 + "@redis/graph": 1.1.1 + "@redis/json": 1.0.7 + "@redis/search": 1.2.0 + "@redis/time-series": 1.1.0 + checksum: 625172dd913118241288c33f351cda42630819bc82a1dc31f22e1d3e0a4267075ecb851aecfaf106a0c73ff287a434a3df3d2a8ce46713acf68d34d66efc39ec + languageName: node + linkType: hard + "redux-immutable@npm:^4.0.0": version: 4.0.0 resolution: "redux-immutable@npm:4.0.0" @@ -40115,6 +42357,13 @@ __metadata: languageName: node linkType: hard +"require-like@npm:>= 0.1.1": + version: 0.1.2 + resolution: "require-like@npm:0.1.2" + checksum: edb8331f05fd807381a75b76f6cca9f0ce8acaa2e910b7e116541799aa970bfbc64fde5fd6adb3a6917dba346f8386ebbddb81614c24e8dad1b4290c7af9535e + languageName: node + linkType: hard + "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -40190,7 +42439,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.22.8, resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:~1.22.1, resolve@npm:~1.22.2": +"resolve@npm:1.22.8, resolve@npm:^1.1.6, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:~1.22.1, resolve@npm:~1.22.2": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -40216,7 +42465,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@1.22.8#~builtin, resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@~1.22.1#~builtin, resolve@patch:resolve@~1.22.2#~builtin": +"resolve@patch:resolve@1.22.8#~builtin, resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.4#~builtin, resolve@patch:resolve@^1.22.8#~builtin, resolve@patch:resolve@~1.22.1#~builtin, resolve@patch:resolve@~1.22.2#~builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#~builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -40260,6 +42509,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^3.0.0": + version: 3.0.0 + resolution: "responselike@npm:3.0.0" + dependencies: + lowercase-keys: ^3.0.0 + checksum: e0cc9be30df4f415d6d83cdede3c5c887cd4a73e7cc1708bcaab1d50a28d15acb68460ac5b02bcc55a42f3d493729c8856427dcf6e57e6e128ad05cba4cfb95e + languageName: node + linkType: hard + "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -40518,28 +42776,28 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.0.0, rollup@npm:^4.20.0": - version: 4.27.2 - resolution: "rollup@npm:4.27.2" +"rollup@npm:^4.20.0, rollup@npm:^4.27.3": + version: 4.27.4 + resolution: "rollup@npm:4.27.4" dependencies: - "@rollup/rollup-android-arm-eabi": 4.27.2 - "@rollup/rollup-android-arm64": 4.27.2 - "@rollup/rollup-darwin-arm64": 4.27.2 - "@rollup/rollup-darwin-x64": 4.27.2 - "@rollup/rollup-freebsd-arm64": 4.27.2 - "@rollup/rollup-freebsd-x64": 4.27.2 - "@rollup/rollup-linux-arm-gnueabihf": 4.27.2 - "@rollup/rollup-linux-arm-musleabihf": 4.27.2 - "@rollup/rollup-linux-arm64-gnu": 4.27.2 - "@rollup/rollup-linux-arm64-musl": 4.27.2 - "@rollup/rollup-linux-powerpc64le-gnu": 4.27.2 - "@rollup/rollup-linux-riscv64-gnu": 4.27.2 - "@rollup/rollup-linux-s390x-gnu": 4.27.2 - "@rollup/rollup-linux-x64-gnu": 4.27.2 - "@rollup/rollup-linux-x64-musl": 4.27.2 - "@rollup/rollup-win32-arm64-msvc": 4.27.2 - "@rollup/rollup-win32-ia32-msvc": 4.27.2 - "@rollup/rollup-win32-x64-msvc": 4.27.2 + "@rollup/rollup-android-arm-eabi": 4.27.4 + "@rollup/rollup-android-arm64": 4.27.4 + "@rollup/rollup-darwin-arm64": 4.27.4 + "@rollup/rollup-darwin-x64": 4.27.4 + "@rollup/rollup-freebsd-arm64": 4.27.4 + "@rollup/rollup-freebsd-x64": 4.27.4 + "@rollup/rollup-linux-arm-gnueabihf": 4.27.4 + "@rollup/rollup-linux-arm-musleabihf": 4.27.4 + "@rollup/rollup-linux-arm64-gnu": 4.27.4 + "@rollup/rollup-linux-arm64-musl": 4.27.4 + "@rollup/rollup-linux-powerpc64le-gnu": 4.27.4 + "@rollup/rollup-linux-riscv64-gnu": 4.27.4 + "@rollup/rollup-linux-s390x-gnu": 4.27.4 + "@rollup/rollup-linux-x64-gnu": 4.27.4 + "@rollup/rollup-linux-x64-musl": 4.27.4 + "@rollup/rollup-win32-arm64-msvc": 4.27.4 + "@rollup/rollup-win32-ia32-msvc": 4.27.4 + "@rollup/rollup-win32-x64-msvc": 4.27.4 "@types/estree": 1.0.6 fsevents: ~2.3.2 dependenciesMeta: @@ -40583,7 +42841,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 582550feaa4e782c22ae8c0f02c3d6b21a43d8e60de0cc7e89534d7023df90fb511b20871d349c7ee69357eb445653fa3e7d48fef8a2d1f9c178cbdbf2b85cd4 + checksum: 7268678ce9a645fda79efa2dc3c9b458357683b0bbd8cc44f8e52d406df4d40468ea3efdf24ad01e25210594cd40902b2b3d20730e2d58e9b226cb3c48dcbd8b languageName: node linkType: hard @@ -40602,9 +42860,10 @@ __metadata: "@octokit/rest": ^19.0.3 "@playwright/test": ^1.32.3 "@spotify/eslint-plugin": ^15.0.0 - "@spotify/prettier-config": ^15.0.0 "@techdocs/cli": "workspace:*" + "@types/cacheable-request": ^8.3.6 "@types/global-agent": ^2.1.3 + "@types/memjs": ^1.3.3 "@types/node": ^20.16.0 "@types/webpack": ^5.28.0 "@useoptic/optic": ^1.0.0 @@ -40949,7 +43208,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.6.3, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0": +"semver@npm:7.6.3, semver@npm:^7.1.1, semver@npm:^7.1.2, semver@npm:^7.1.3, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.2": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -41359,13 +43618,6 @@ __metadata: languageName: node linkType: hard -"slash@npm:^4.0.0": - version: 4.0.0 - resolution: "slash@npm:4.0.0" - checksum: da8e4af73712253acd21b7853b7e0dbba776b786e82b010a5bfc8b5051a1db38ed8aba8e1e8f400dd2c9f373be91eb1c42b66e91abb407ff42b10feece5e1d2d - languageName: node - linkType: hard - "slash@npm:^5.1.0": version: 5.1.0 resolution: "slash@npm:5.1.0" @@ -41436,10 +43688,10 @@ __metadata: languageName: node linkType: hard -"smol-toml@npm:^1.3.0": - version: 1.3.0 - resolution: "smol-toml@npm:1.3.0" - checksum: 79e1db6b6cd32a13ad7602bfe1a02f20894fe599657a5cc2c8ffab7c3de4ba51f7426b701b513f9b859560918b36a63f7c73f7eaf6def8a1dc73db74ffd9b601 +"smol-toml@npm:^1.3.1": + version: 1.3.1 + resolution: "smol-toml@npm:1.3.1" + checksum: dc3284a674065874b1d34a945709ce3da2a0c44b1ff86b3274615d322c2f6cf8e5d2f5f7d569fd92330ec08590777972725e7d3ba856bd6d841243673064994e languageName: node linkType: hard @@ -41485,14 +43737,14 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^8.0.1, socks-proxy-agent@npm:^8.0.2, socks-proxy-agent@npm:^8.0.4": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" +"socks-proxy-agent@npm:^8.0.1, socks-proxy-agent@npm:^8.0.2, socks-proxy-agent@npm:^8.0.3, socks-proxy-agent@npm:^8.0.4": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" dependencies: - agent-base: ^7.1.1 + agent-base: ^7.1.2 debug: ^4.3.4 socks: ^2.8.3 - checksum: b2ec5051d85fe49072f9a250c427e0e9571fd09d5db133819192d078fd291276e1f0f50f6dbc04329b207738b1071314cee8bdbb4b12e27de42dbcf1d4233c67 + checksum: b4fbcdb7ad2d6eec445926e255a1fb95c975db0020543fbac8dfa6c47aecc6b3b619b7fb9c60a3f82c9b2969912a5e7e174a056ae4d98cb5322f3524d6036e1d languageName: node linkType: hard @@ -41524,20 +43776,20 @@ __metadata: linkType: hard "sort-package-json@npm:^2.8.0": - version: 2.10.1 - resolution: "sort-package-json@npm:2.10.1" + version: 2.12.0 + resolution: "sort-package-json@npm:2.12.0" dependencies: detect-indent: ^7.0.1 detect-newline: ^4.0.0 get-stdin: ^9.0.0 git-hooks-list: ^3.0.0 - globby: ^13.1.2 is-plain-obj: ^4.1.0 semver: ^7.6.0 sort-object-keys: ^1.1.3 + tinyglobby: ^0.2.9 bin: sort-package-json: cli.js - checksum: 861d8161565fba322414d70b6be10fb331680549b73399778965be628783833c85c4e02929bcea5a2d96994884b0327dfe2f7c7a79409c901d2582b703f5333d + checksum: c4bd25516b0e23c83a6c0f9ad418869a4b09675628e96f8c44b6b1f3458fbbd8a84d623ed63e24af620675977ab8a867e0f5356fc3cc4f9c7be85dcd3136d4ac languageName: node linkType: hard @@ -41638,13 +43890,13 @@ __metadata: languageName: node linkType: hard -"spawndamnit@npm:^2.0.0": - version: 2.0.0 - resolution: "spawndamnit@npm:2.0.0" +"spawndamnit@npm:^3.0.1": + version: 3.0.1 + resolution: "spawndamnit@npm:3.0.1" dependencies: - cross-spawn: ^5.1.0 - signal-exit: ^3.0.2 - checksum: c74b5e264ee5bc13d55692fd422d74c282e4607eb04ac64d19d06796718d89b14921620fa4237ec5635e7acdff21461670ff19850f210225410a353cad0d7fed + cross-spawn: ^7.0.5 + signal-exit: ^4.0.1 + checksum: 47d88a7f1e5691e13e435eddc3d34123c2f7746e2853e91bfac5ea7c6e3bb4b1d1995223b25f7a8745871510d92f63ecd3c9fa02aa2896ac0c79fb618eb08bbe languageName: node linkType: hard @@ -41794,6 +44046,15 @@ __metadata: languageName: node linkType: hard +"ssri@npm:^12.0.0": + version: 12.0.0 + resolution: "ssri@npm:12.0.0" + dependencies: + minipass: ^7.0.3 + checksum: ef4b6b0ae47b4a69896f5f1c4375f953b9435388c053c36d27998bc3d73e046969ccde61ab659e679142971a0b08e50478a1228f62edb994105b280f17900c98 + languageName: node + linkType: hard + "ssri@npm:^6.0.1": version: 6.0.2 resolution: "ssri@npm:6.0.2" @@ -41853,10 +44114,10 @@ __metadata: languageName: node linkType: hard -"stackframe@npm:^1.1.1": - version: 1.1.1 - resolution: "stackframe@npm:1.1.1" - checksum: 6031b30cc070972be6b12f4f4109e62150912ddbc8d6d2bc1707387bfa74b69ec298aa1211b9bf8dc4cf4f5245a5cdb72dda4b7c0467ea0cce2d10e4f10ffe3a +"stackframe@npm:^1.1.1, stackframe@npm:^1.3.4": + version: 1.3.4 + resolution: "stackframe@npm:1.3.4" + checksum: bae1596873595c4610993fa84f86a3387d67586401c1816ea048c0196800c0646c4d2da98c2ee80557fd9eff05877efe33b91ba6cd052658ed96ddc85d19067d languageName: node linkType: hard @@ -41918,6 +44179,24 @@ __metadata: languageName: node linkType: hard +"storybook@npm:^8.4.6": + version: 8.4.6 + resolution: "storybook@npm:8.4.6" + dependencies: + "@storybook/core": 8.4.6 + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + bin: + getstorybook: ./bin/index.cjs + sb: ./bin/index.cjs + storybook: ./bin/index.cjs + checksum: af1295778a99d504f6200d9594a517a58e0e8ccf2d5f2706e9716eb2e60ac4475bb558d811d4b51bc7feb0c21701a3801e09a4d52b453e1f94ce28b13be1a50f + languageName: node + linkType: hard + "stream-browserify@npm:3.0.0, stream-browserify@npm:^3.0.0": version: 3.0.0 resolution: "stream-browserify@npm:3.0.0" @@ -42320,6 +44599,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^4.0.0": + version: 4.0.0 + resolution: "strip-indent@npm:4.0.0" + dependencies: + min-indent: ^1.0.1 + checksum: 06cbcd93da721c46bc13caeb1c00af93a9b18146a1c95927672d2decab6a25ad83662772417cea9317a2507fb143253ecc23c4415b64f5828cef9b638a744598 + languageName: node + linkType: hard + "strip-json-comments@npm:5.0.1": version: 5.0.1 resolution: "strip-json-comments@npm:5.0.1" @@ -42683,6 +44971,13 @@ __metadata: languageName: node linkType: hard +"tabbable@npm:^6.0.0": + version: 6.2.0 + resolution: "tabbable@npm:6.2.0" + checksum: f8440277d223949272c74bb627a3371be21735ca9ad34c2570f7e1752bd646ccfc23a9d8b1ee65d6561243f4134f5fbbf1ad6b39ac3c4b586554accaff4a1300 + languageName: node + linkType: hard + "tapable@npm:^1.0.0": version: 1.1.3 resolution: "tapable@npm:1.1.3" @@ -42776,7 +45071,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^7.0.0": +"tar@npm:^7.0.0, tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" dependencies: @@ -42886,7 +45181,7 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.10": +"terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3, terser-webpack-plugin@npm:^5.3.1, terser-webpack-plugin@npm:^5.3.10": version: 5.3.10 resolution: "terser-webpack-plugin@npm:5.3.10" dependencies: @@ -43082,7 +45377,7 @@ __metadata: languageName: node linkType: hard -"tiny-invariant@npm:^1.0.6, tiny-invariant@npm:^1.3.3": +"tiny-invariant@npm:^1.0.6, tiny-invariant@npm:^1.3.1, tiny-invariant@npm:^1.3.3": version: 1.3.3 resolution: "tiny-invariant@npm:1.3.3" checksum: 5e185c8cc2266967984ce3b352a4e57cb89dad5a8abb0dea21468a6ecaa67cd5bb47a3b7a85d08041008644af4f667fb8b6575ba38ba5fb00b3b5068306e59fe @@ -43184,13 +45479,6 @@ __metadata: languageName: node linkType: hard -"to-fast-properties@npm:^2.0.0": - version: 2.0.0 - resolution: "to-fast-properties@npm:2.0.0" - checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 - languageName: node - linkType: hard - "to-readable-stream@npm:^1.0.0": version: 1.0.0 resolution: "to-readable-stream@npm:1.0.0" @@ -43403,6 +45691,13 @@ __metadata: languageName: node linkType: hard +"ts-dedent@npm:^2.0.0, ts-dedent@npm:^2.2.0": + version: 2.2.0 + resolution: "ts-dedent@npm:2.2.0" + checksum: 93ed8f7878b6d5ed3c08d99b740010eede6bccfe64bce61c5a4da06a2c17d6ddbb80a8c49c2d15251de7594a4f93ffa21dd10e7be75ef66a4dc9951b4a94e2af + languageName: node + linkType: hard + "ts-easing@npm:^0.2.0": version: 0.2.0 resolution: "ts-easing@npm:0.2.0" @@ -43514,6 +45809,17 @@ __metadata: languageName: node linkType: hard +"tsconfig-paths@npm:^4.2.0": + version: 4.2.0 + resolution: "tsconfig-paths@npm:4.2.0" + dependencies: + json5: ^2.2.2 + minimist: ^1.2.6 + strip-bom: ^3.0.0 + checksum: 28c5f7bbbcabc9dabd4117e8fdc61483f6872a1c6b02a4b1c4d68c5b79d06896c3cc9547610c4c3ba64658531caa2de13ead1ea1bf321c7b53e969c4752b98c7 + languageName: node + linkType: hard + "tslib@npm:2.7.0": version: 2.7.0 resolution: "tslib@npm:2.7.0" @@ -43583,6 +45889,13 @@ __metadata: languageName: node linkType: hard +"tween-functions@npm:^1.2.0": + version: 1.2.0 + resolution: "tween-functions@npm:1.2.0" + checksum: 880708d680eff5c347ddcb9f922ad121703a91c78ce308ed309073e73a794b633eb0b80589a839365803f150515ad34c9646809ae8a0e90f09e62686eefb1ab6 + languageName: node + linkType: hard + "tweetnacl@npm:^0.14.3, tweetnacl@npm:~0.14.0": version: 0.14.5 resolution: "tweetnacl@npm:0.14.5" @@ -43891,6 +46204,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.5.4": + version: 1.5.4 + resolution: "ufo@npm:1.5.4" + checksum: f244703b7d4f9f0df4f9af23921241ab73410b591f4e5b39c23e3147f3159b139a4b1fb5903189c306129f7a16b55995dac0008e0fbae88a37c3e58cbc34d833 + languageName: node + linkType: hard + "uglify-js@npm:^3.1.4": version: 3.17.0 resolution: "uglify-js@npm:3.17.0" @@ -43972,13 +46292,20 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~6.19.2, undici-types@npm:~6.19.8": +"undici-types@npm:~6.19.2": version: 6.19.8 resolution: "undici-types@npm:6.19.8" checksum: de51f1b447d22571cf155dfe14ff6d12c5bdaec237c765085b439c38ca8518fc360e88c70f99469162bf2e14188a7b0bcb06e1ed2dc031042b984b0bb9544017 languageName: node linkType: hard +"undici-types@npm:~6.20.0": + version: 6.20.0 + resolution: "undici-types@npm:6.20.0" + checksum: b7bc50f012dc6afbcce56c9fd62d7e86b20a62ff21f12b7b5cbf1973b9578d90f22a9c7fe50e638e96905d33893bf2f9f16d98929c4673c2480de05c6c96ea8b + languageName: node + linkType: hard + "undici@npm:^5.28.4": version: 5.28.4 resolution: "undici@npm:5.28.4" @@ -44068,6 +46395,15 @@ __metadata: languageName: node linkType: hard +"unique-filename@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-filename@npm:4.0.0" + dependencies: + unique-slug: ^5.0.0 + checksum: 6a62094fcac286b9ec39edbd1f8f64ff92383baa430af303dfed1ffda5e47a08a6b316408554abfddd9730c78b6106bef4ca4d02c1231a735ddd56ced77573df + languageName: node + linkType: hard + "unique-slug@npm:^2.0.0": version: 2.0.2 resolution: "unique-slug@npm:2.0.2" @@ -44086,6 +46422,15 @@ __metadata: languageName: node linkType: hard +"unique-slug@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-slug@npm:5.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: 222d0322bc7bbf6e45c08967863212398313ef73423f4125e075f893a02405a5ffdbaaf150f7dd1e99f8861348a486dd079186d27c5f2c60e465b7dcbb1d3e5b + languageName: node + linkType: hard + "unique-string@npm:^2.0.0": version: 2.0.0 resolution: "unique-string@npm:2.0.0" @@ -44230,6 +46575,16 @@ __metadata: languageName: node linkType: hard +"unplugin@npm:^1.3.1": + version: 1.16.0 + resolution: "unplugin@npm:1.16.0" + dependencies: + acorn: ^8.14.0 + webpack-virtual-modules: ^0.6.2 + checksum: 84bff88dd8fd6ba88bd21dad1b170fea2a91f7ff8ddcfadf826297cf77dfe305f3428f1612c0637f30d7ac10d668491f15fdf8f378dd56def370fdbc16edd85e + languageName: node + linkType: hard + "unraw@npm:^3.0.0": version: 3.0.0 resolution: "unraw@npm:3.0.0" @@ -44251,17 +46606,17 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.1.0": - version: 1.1.0 - resolution: "update-browserslist-db@npm:1.1.0" +"update-browserslist-db@npm:^1.1.1": + version: 1.1.1 + resolution: "update-browserslist-db@npm:1.1.1" dependencies: - escalade: ^3.1.2 - picocolors: ^1.0.1 + escalade: ^3.2.0 + picocolors: ^1.1.0 peerDependencies: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: 7b74694d96f0c360f01b702e72353dc5a49df4fe6663d3ee4e5c628f061576cddf56af35a3a886238c01dd3d8f231b7a86a8ceaa31e7a9220ae31c1c1238e562 + checksum: 2ea11bd2562122162c3e438d83a1f9125238c0844b6d16d366e3276d0c0acac6036822dc7df65fc5a89c699cdf9f174acf439c39bedf3f9a2f3983976e4b4c3e languageName: node linkType: hard @@ -44338,6 +46693,13 @@ __metadata: languageName: node linkType: hard +"url-template@npm:^2.0.8": + version: 2.0.8 + resolution: "url-template@npm:2.0.8" + checksum: 4183fccd74e3591e4154134d4443dccecba9c455c15c7df774f1f1e3fa340fd9bffb903b5beec347196d15ce49c34edf6dec0634a95d170ad6e78c0467d6e13e + languageName: node + linkType: hard + "url-value-parser@npm:^2.0.0": version: 2.0.3 resolution: "url-value-parser@npm:2.0.3" @@ -44466,12 +46828,12 @@ __metadata: languageName: node linkType: hard -"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0": - version: 1.2.0 - resolution: "use-sync-external-store@npm:1.2.0" +"use-sync-external-store@npm:^1.0.0, use-sync-external-store@npm:^1.2.0, use-sync-external-store@npm:^1.2.2": + version: 1.2.2 + resolution: "use-sync-external-store@npm:1.2.2" peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 5c639e0f8da3521d605f59ce5be9e094ca772bd44a4ce7322b055a6f58eeed8dda3c94cabd90c7a41fb6fa852210092008afe48f7038792fd47501f33299116a + checksum: fe07c071c4da3645f112c38c0e57beb479a8838616ff4e92598256ecce527f2888c08febc7f9b2f0ce2f0e18540ba3cde41eb2035e4fafcb4f52955037098a81 languageName: node linkType: hard @@ -44543,7 +46905,7 @@ __metadata: languageName: node linkType: hard -"uuid@npm:^11.0.0": +"uuid@npm:^11.0.0, uuid@npm:^11.0.2": version: 11.0.3 resolution: "uuid@npm:11.0.3" bin: @@ -44748,6 +47110,21 @@ __metadata: languageName: node linkType: hard +"vite-node@npm:^1.2.0": + version: 1.6.0 + resolution: "vite-node@npm:1.6.0" + dependencies: + cac: ^6.7.14 + debug: ^4.3.4 + pathe: ^1.1.1 + picocolors: ^1.0.0 + vite: ^5.0.0 + bin: + vite-node: vite-node.mjs + checksum: ce111c5c7a4cf65b722baa15cbc065b7bfdbf1b65576dd6372995f6a72b2b93773ec5df59f6c5f08cfe1284806597b44b832efcea50d5971102428159ff4379f + languageName: node + linkType: hard + "vite-plugin-html@npm:^3.2.2": version: 3.2.2 resolution: "vite-plugin-html@npm:3.2.2" @@ -44782,7 +47159,7 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.0.0": +"vite@npm:^5.0.0, vite@npm:^5.0.11": version: 5.4.11 resolution: "vite@npm:5.4.11" dependencies: @@ -44972,6 +47349,24 @@ __metadata: languageName: node linkType: hard +"webpack-dev-middleware@npm:^6.1.2": + version: 6.1.3 + resolution: "webpack-dev-middleware@npm:6.1.3" + dependencies: + colorette: ^2.0.10 + memfs: ^3.4.12 + mime-types: ^2.1.31 + range-parser: ^1.2.1 + schema-utils: ^4.0.0 + peerDependencies: + webpack: ^5.0.0 + peerDependenciesMeta: + webpack: + optional: true + checksum: ddedaa913cc39d7ac7f971d902f181ecc5c4ab0b91f9eda5923f0ea513ecf458f71046f2ed423cb4fc657c2177fe279186453e395bd1051f0949e265c3124665 + languageName: node + linkType: hard + "webpack-dev-middleware@npm:^7.1.0, webpack-dev-middleware@npm:^7.4.2": version: 7.4.2 resolution: "webpack-dev-middleware@npm:7.4.2" @@ -45083,6 +47478,28 @@ __metadata: languageName: node linkType: hard +"webpack-hot-middleware@npm:^2.25.1": + version: 2.26.1 + resolution: "webpack-hot-middleware@npm:2.26.1" + dependencies: + ansi-html-community: 0.0.8 + html-entities: ^2.1.0 + strip-ansi: ^6.0.0 + checksum: 78513d8d5770c59c3039ce094c49b2e2772b3f1d4ec5c124a7aabe6124a0e08429993b81129649087dc300f496822257e39135bf8b891b51aea197c1b554072a + languageName: node + linkType: hard + +"webpack-merge@npm:^6.0.1": + version: 6.0.1 + resolution: "webpack-merge@npm:6.0.1" + dependencies: + clone-deep: ^4.0.1 + flat: ^5.0.2 + wildcard: ^2.0.1 + checksum: e8a604c686b944605a1c57cc7b75e886ab902dc5ffdd15259a092c5c2dd5f58868fe39f995ea4bad4f189e38843b061c4ae1eb22822d7169813f4adab571dc3d + languageName: node + linkType: hard + "webpack-sources@npm:^1.4.3": version: 1.4.3 resolution: "webpack-sources@npm:1.4.3" @@ -45100,17 +47517,24 @@ __metadata: languageName: node linkType: hard -"webpack@npm:^5, webpack@npm:^5.94.0": - version: 5.95.0 - resolution: "webpack@npm:5.95.0" +"webpack-virtual-modules@npm:^0.6.0, webpack-virtual-modules@npm:^0.6.2": + version: 0.6.2 + resolution: "webpack-virtual-modules@npm:0.6.2" + checksum: 7e8e1d63f35864c815420cc2f27da8561a1e028255040698a352717de0ba46d3b3faf16f06c1a1965217054c4c2894eb9af53a85451870e919b5707ce9c5822d + languageName: node + linkType: hard + +"webpack@npm:5, webpack@npm:^5, webpack@npm:^5.94.0": + version: 5.96.1 + resolution: "webpack@npm:5.96.1" dependencies: - "@types/estree": ^1.0.5 + "@types/eslint-scope": ^3.7.7 + "@types/estree": ^1.0.6 "@webassemblyjs/ast": ^1.12.1 "@webassemblyjs/wasm-edit": ^1.12.1 "@webassemblyjs/wasm-parser": ^1.12.1 - acorn: ^8.7.1 - acorn-import-attributes: ^1.9.5 - browserslist: ^4.21.10 + acorn: ^8.14.0 + browserslist: ^4.24.0 chrome-trace-event: ^1.0.2 enhanced-resolve: ^5.17.1 es-module-lexer: ^1.2.1 @@ -45132,7 +47556,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 0c3dfe288de4d62f8f3dc25478a618894883cab739121330763b7847e43304630ea2815ae2351a5f8ff6ab7c9642caf530d503d89bda261fe2cd220e524dd5d1 + checksum: ec3662f64895fae408440a997f87299e374c9d9f911f77b880bab46402f52221c7836bdf101fc2556338d07fc7cb86da50661f944eb1d1041a8361a5b9247876 languageName: node linkType: hard @@ -45317,6 +47741,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^5.0.0": + version: 5.0.0 + resolution: "which@npm:5.0.0" + dependencies: + isexe: ^3.1.1 + bin: + node-which: bin/which.js + checksum: 6ec99e89ba32c7e748b8a3144e64bfc74aa63e2b2eacbb61a0060ad0b961eb1a632b08fb1de067ed59b002cec3e21de18299216ebf2325ef0f78e0f121e14e90 + languageName: node + linkType: hard + "wide-align@npm:^1.1.2": version: 1.1.5 resolution: "wide-align@npm:1.1.5" @@ -45335,6 +47770,13 @@ __metadata: languageName: node linkType: hard +"wildcard@npm:^2.0.1": + version: 2.0.1 + resolution: "wildcard@npm:2.0.1" + checksum: e0c60a12a219e4b12065d1199802d81c27b841ed6ad6d9d28240980c73ceec6f856771d575af367cbec2982d9ae7838759168b551776577f155044f5a5ba843c + languageName: node + linkType: hard + "winston-transport@npm:^4.5.0, winston-transport@npm:^4.7.0": version: 4.8.0 resolution: "winston-transport@npm:4.8.0" @@ -45462,7 +47904,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:*, ws@npm:8.18.0, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.8.0": +"ws@npm:*, ws@npm:8.18.0, ws@npm:^8.11.0, ws@npm:^8.12.0, ws@npm:^8.13.0, ws@npm:^8.16.0, ws@npm:^8.17.1, ws@npm:^8.18.0, ws@npm:^8.2.3, ws@npm:^8.8.0": version: 8.18.0 resolution: "ws@npm:8.18.0" peerDependencies: @@ -45649,10 +48091,10 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^2.1.2": - version: 2.1.2 - resolution: "yallist@npm:2.1.2" - checksum: 9ba99409209f485b6fcb970330908a6d41fa1c933f75e08250316cce19383179a6b70a7e0721b89672ebb6199cc377bf3e432f55100da6a7d6e11902b0a642cb +"yallist@npm:4.0.0, yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 languageName: node linkType: hard @@ -45663,13 +48105,6 @@ __metadata: languageName: node linkType: hard -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 - languageName: node - linkType: hard - "yallist@npm:^5.0.0": version: 5.0.0 resolution: "yallist@npm:5.0.0" @@ -45706,21 +48141,12 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4": - version: 2.6.0 - resolution: "yaml@npm:2.6.0" +"yaml@npm:^2.0.0, yaml@npm:^2.0.0-10, yaml@npm:^2.1.1, yaml@npm:^2.2.1, yaml@npm:^2.2.2, yaml@npm:^2.3.2, yaml@npm:^2.3.3, yaml@npm:^2.3.4, yaml@npm:~2.6.1": + version: 2.6.1 + resolution: "yaml@npm:2.6.1" bin: yaml: bin.mjs - checksum: e5e74fd75e01bde2c09333d529af9fbb5928c5f7f01bfdefdcb2bf753d4ef489a45cab4deac01c9448f55ca27e691612b81fe3c3a59bb8cb5b0069da0f92cf0b - languageName: node - linkType: hard - -"yaml@npm:~2.5.0": - version: 2.5.1 - resolution: "yaml@npm:2.5.1" - bin: - yaml: bin.mjs - checksum: 31275223863fbd0b47ba9d2b248fbdf085db8d899e4ca43fff8a3a009497c5741084da6871d11f40e555d61360951c4c910b98216c1325d2c94753c0036d8172 + checksum: 5cf2627f121dcf04ccdebce8e6cbac7c9983d465c4eab314f6fbdc13cda8a07f4e8f9c2252a382b30bcabe05ee3c683647293afd52eb37cbcefbdc7b6ebde9ee languageName: node linkType: hard @@ -45779,8 +48205,7 @@ __metadata: "@yarnpkg/builder": ^4.0.0 "@yarnpkg/core": ^4.0.3 "@yarnpkg/fslib": ^3.0.2 - chalk: ^4.0.0 - lodash: ^4.17.21 + "@yarnpkg/plugin-pack": ^4.0.0 nodemon: ^3.0.1 semver: ^7.6.0 languageName: unknown