diff --git a/.changeset/blue-hairs-prove.md b/.changeset/blue-hairs-prove.md new file mode 100644 index 0000000000..7812825da6 --- /dev/null +++ b/.changeset/blue-hairs-prove.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Linting is now ignored for any `.eslintrc.*` files, not just `.eslintrc.js`. diff --git a/.changeset/cyan-pens-suffer.md b/.changeset/cyan-pens-suffer.md new file mode 100644 index 0000000000..b7d3a3a096 --- /dev/null +++ b/.changeset/cyan-pens-suffer.md @@ -0,0 +1,8 @@ +--- +'@backstage/backend-app-api': patch +'@backstage/backend-plugin-api': patch +'@backstage/backend-test-utils': patch +'@backstage/plugin-catalog-node': patch +--- + +Refactored experimental backend system with new type names. diff --git a/.changeset/fuzzy-months-study.md b/.changeset/fuzzy-months-study.md new file mode 100644 index 0000000000..024349f90b --- /dev/null +++ b/.changeset/fuzzy-months-study.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend': patch +--- + +Fixed a bug in auth plugin on the backend where it ignores the skip migration database options when using the database provider. diff --git a/.changeset/giant-swans-change.md b/.changeset/giant-swans-change.md new file mode 100644 index 0000000000..bff90db2b1 --- /dev/null +++ b/.changeset/giant-swans-change.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-plugin-api': patch +--- + +The factory returned by `createBackendPlugin` and `createBackendModule` no longer require a parameter to be passed if the options are optional. diff --git a/.changeset/late-dolphins-leave.md b/.changeset/late-dolphins-leave.md new file mode 100644 index 0000000000..796b9a7a21 --- /dev/null +++ b/.changeset/late-dolphins-leave.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-graphiql': patch +--- + +Minor internal tweak to lazy loading in order to improve module compatibility. diff --git a/.changeset/selfish-items-play.md b/.changeset/selfish-items-play.md new file mode 100644 index 0000000000..6df9bd0de1 --- /dev/null +++ b/.changeset/selfish-items-play.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-catalog-backend': patch +'@backstage/plugin-catalog-node': patch +'@backstage/plugin-scaffolder-backend': patch +--- + +Fixed typos in alpha types. diff --git a/.changeset/seven-nails-cough.md b/.changeset/seven-nails-cough.md new file mode 100644 index 0000000000..1464e29235 --- /dev/null +++ b/.changeset/seven-nails-cough.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +Added alpha test helpers for the new experimental backend system. diff --git a/.changeset/smooth-planes-itch.md b/.changeset/smooth-planes-itch.md new file mode 100644 index 0000000000..638a2e0bf6 --- /dev/null +++ b/.changeset/smooth-planes-itch.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': patch +--- + +Fail gracefully if an invalid `Authorization` header is passed to `POST /v2/tasks` diff --git a/.changeset/twenty-terms-dress.md b/.changeset/twenty-terms-dress.md new file mode 100644 index 0000000000..99acaf612a --- /dev/null +++ b/.changeset/twenty-terms-dress.md @@ -0,0 +1,14 @@ +--- +'@backstage/create-app': patch +--- + +Updated backend to write stack trace when the backend fails to start up. + +To apply this change to your Backstage installation, make the following change to `packages/backend/src/index.ts` + +```diff + cors: + origin: http://localhost:3000 +- console.error(`Backend failed to start up, ${error}`); ++ console.error('Backend failed to start up', error); +``` diff --git a/.changeset/weak-drinks-report.md b/.changeset/weak-drinks-report.md new file mode 100644 index 0000000000..1f8ee512ba --- /dev/null +++ b/.changeset/weak-drinks-report.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-code-climate': patch +--- + +Send Authorization headers in fetch requests using FetchApi in Code Climate plugin to fix unauthorized requests to Backstage backends with authentication enabled. diff --git a/docs/plugins/customization.md b/docs/plugins/customization.md index 0477ba18a7..44ca5147ea 100644 --- a/docs/plugins/customization.md +++ b/docs/plugins/customization.md @@ -1,6 +1,6 @@ --- id: customization -title: Customization +title: Customization (Experimental) description: Documentation on adding a customization logic to the plugin --- diff --git a/microsite/sidebars.json b/microsite/sidebars.json index 2ae7f5e81d..27ae9c8295 100644 --- a/microsite/sidebars.json +++ b/microsite/sidebars.json @@ -219,6 +219,7 @@ "plugins/integrating-plugin-into-software-catalog", "plugins/integrating-search-into-plugins", "plugins/composability", + "plugins/customization", "plugins/analytics", { "type": "subcategory", diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 130ad6d1f1..26c8179771 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -4,8 +4,9 @@ ```ts import { AnyServiceFactory } from '@backstage/backend-plugin-api'; -import { BackendRegistrable } from '@backstage/backend-plugin-api'; +import { BackendFeature } from '@backstage/backend-plugin-api'; import { Config } from '@backstage/config'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { HttpRouterService } from '@backstage/backend-plugin-api'; import { Logger } from '@backstage/backend-plugin-api'; import { PermissionAuthorizer } from '@backstage/plugin-permission-common'; @@ -15,13 +16,14 @@ import { PluginDatabaseManager } from '@backstage/backend-common'; import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { PluginTaskScheduler } from '@backstage/backend-tasks'; import { ServiceFactory } from '@backstage/backend-plugin-api'; +import { ServiceRef } from '@backstage/backend-plugin-api'; import { TokenManager } from '@backstage/backend-common'; import { UrlReader } from '@backstage/backend-common'; // @public (undocumented) export interface Backend { // (undocumented) - add(extension: BackendRegistrable): void; + add(feature: BackendFeature): void; // (undocumented) start(): Promise; } @@ -85,6 +87,11 @@ export const schedulerFactory: ServiceFactory< {} >; +// @public (undocumented) +export type ServiceOrExtensionPoint = + | ExtensionPoint + | ServiceRef; + // @public (undocumented) export const tokenManagerFactory: ServiceFactory< TokenManager, diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index ab086f4144..afb5250504 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -15,19 +15,21 @@ */ import { - BackendRegistrable, + BackendFeature, ExtensionPoint, ServiceRef, } from '@backstage/backend-plugin-api'; -import { BackendRegisterInit, ServiceHolder } from './types'; - -type ServiceOrExtensionPoint = ExtensionPoint | ServiceRef; +import { + BackendRegisterInit, + ServiceHolder, + ServiceOrExtensionPoint, +} from './types'; export class BackendInitializer { #started = false; - #extensions = new Map(); + #features = new Map(); #registerInits = new Array(); - #extensionPoints = new Map(); + #extensionPoints = new Map, unknown>(); #serviceHolder: ServiceHolder; constructor(serviceHolder: ServiceHolder) { @@ -38,42 +40,56 @@ export class BackendInitializer { deps: { [name: string]: ServiceOrExtensionPoint }, pluginId: string, ) { - return Object.fromEntries( - await Promise.all( - Object.entries(deps).map(async ([name, ref]) => [ - name, - this.#extensionPoints.get(ref) || - (await this.#serviceHolder.get(ref as ServiceRef)!( - pluginId, - )), - ]), - ), - ); - } + const result = new Map(); + const missingRefs = new Set(); - add(extension: BackendRegistrable, options?: TOptions) { - if (this.#started) { + for (const [name, ref] of Object.entries(deps)) { + const extensionPoint = this.#extensionPoints.get( + ref as ExtensionPoint, + ); + if (extensionPoint) { + result.set(name, extensionPoint); + } else { + const factory = await this.#serviceHolder.get( + ref as ServiceRef, + ); + if (factory) { + result.set(name, await factory(pluginId)); + } else { + missingRefs.add(ref); + } + } + } + + if (missingRefs.size > 0) { + const missing = Array.from(missingRefs).join(', '); throw new Error( - 'extension can not be added after the backend has started', + `No extension point or service available for the following ref(s): ${missing}`, ); } - this.#extensions.set(extension, options); + + return Object.fromEntries(result); + } + + add(feature: BackendFeature, options?: TOptions) { + if (this.#started) { + throw new Error('feature can not be added after the backend has started'); + } + this.#features.set(feature, options); } async start(): Promise { - console.log(`Starting backend`); if (this.#started) { throw new Error('Backend has already started'); } this.#started = true; - for (const [extension] of this.#extensions) { - const provides = new Set>(); + for (const [feature] of this.#features) { + const provides = new Set>(); let registerInit: BackendRegisterInit | undefined = undefined; - console.log('Registering', extension.id); - extension.register({ + feature.register({ registerExtensionPoint: (extensionPointRef, impl) => { if (registerInit) { throw new Error('registerExtensionPoint called after registerInit'); @@ -89,7 +105,7 @@ export class BackendInitializer { throw new Error('registerInit must only be called once'); } registerInit = { - id: extension.id, + id: feature.id, provides, consumes: new Set(Object.values(registerOptions.deps)), deps: registerOptions.deps, @@ -100,15 +116,13 @@ export class BackendInitializer { if (!registerInit) { throw new Error( - `registerInit was not called by register in ${extension.id}`, + `registerInit was not called by register in ${feature.id}`, ); } this.#registerInits.push(registerInit); } - this.validateSetup(); - const orderedRegisterResults = this.#resolveInitOrder(this.#registerInits); for (const registerInit of orderedRegisterResults) { @@ -117,8 +131,6 @@ export class BackendInitializer { } } - private validateSetup() {} - #resolveInitOrder(registerInits: Array) { let registerInitsToOrder = registerInits.slice(); const orderedRegisterInits = new Array(); @@ -131,18 +143,17 @@ export class BackendInitializer { for (const registerInit of registerInitsToOrder) { const unInitializedDependents = []; - for (const serviceRef of registerInit.provides) { + for (const provided of registerInit.provides) { if ( registerInitsToOrder.some( - init => init !== registerInit && init.consumes.has(serviceRef), + init => init !== registerInit && init.consumes.has(provided), ) ) { - unInitializedDependents.push(serviceRef); + unInitializedDependents.push(provided); } } if (unInitializedDependents.length === 0) { - console.log(`DEBUG: pushed ${registerInit.id} to results`); orderedRegisterInits.push(registerInit); toRemove.add(registerInit); } @@ -150,6 +161,7 @@ export class BackendInitializer { registerInitsToOrder = registerInitsToOrder.filter(r => !toRemove.has(r)); } + return orderedRegisterInits; } } diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts index 104d2b6fc8..1e09ed77ba 100644 --- a/packages/backend-app-api/src/wiring/BackstageBackend.ts +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -16,7 +16,7 @@ import { AnyServiceFactory, - BackendRegistrable, + BackendFeature, } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; import { ServiceRegistry } from './ServiceRegistry'; @@ -31,8 +31,8 @@ export class BackstageBackend implements Backend { this.#initializer = new BackendInitializer(this.#services); } - add(extension: BackendRegistrable): void { - this.#initializer.add(extension); + add(feature: BackendFeature): void { + this.#initializer.add(feature); } async start(): Promise { diff --git a/packages/backend-app-api/src/wiring/index.ts b/packages/backend-app-api/src/wiring/index.ts index d6e4de9145..2f55076922 100644 --- a/packages/backend-app-api/src/wiring/index.ts +++ b/packages/backend-app-api/src/wiring/index.ts @@ -14,5 +14,9 @@ * limitations under the License. */ -export type { Backend, CreateSpecializedBackendOptions } from './types'; +export type { + Backend, + CreateSpecializedBackendOptions, + ServiceOrExtensionPoint, +} from './types'; export { createSpecializedBackend } from './types'; diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index 2aaead805d..0ca40b5660 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -16,7 +16,8 @@ import { AnyServiceFactory, - BackendRegistrable, + BackendFeature, + ExtensionPoint, FactoryFunc, ServiceRef, } from '@backstage/backend-plugin-api'; @@ -26,15 +27,15 @@ import { BackstageBackend } from './BackstageBackend'; * @public */ export interface Backend { - add(extension: BackendRegistrable): void; + add(feature: BackendFeature): void; start(): Promise; } export interface BackendRegisterInit { id: string; - consumes: Set>; - provides: Set>; - deps: { [name: string]: ServiceRef }; + consumes: Set; + provides: Set; + deps: { [name: string]: ServiceOrExtensionPoint }; init: (deps: { [name: string]: unknown }) => Promise; } @@ -57,3 +58,10 @@ export function createSpecializedBackend( ): Backend { return new BackstageBackend(options.services); } + +/** + * @public + */ +export type ServiceOrExtensionPoint = + | ExtensionPoint + | ServiceRef; diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index df8474d670..fa5097be64 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -26,23 +26,11 @@ export type AnyServiceFactory = ServiceFactory< >; // @public (undocumented) -export interface BackendInitRegistry { +export interface BackendFeature { // (undocumented) - registerExtensionPoint( - ref: ServiceRef, - impl: TExtensionPoint, - ): void; + id: string; // (undocumented) - registerInit< - Deps extends { - [name in string]: unknown; - }, - >(options: { - deps: { - [name in keyof Deps]: ServiceRef; - }; - init: (deps: Deps) => Promise; - }): void; + register(reg: BackendRegistrationPoints): void; } // @public (undocumented) @@ -53,7 +41,7 @@ export interface BackendModuleConfig { pluginId: string; // (undocumented) register( - reg: Omit, + reg: Omit, options: TOptions, ): void; } @@ -63,15 +51,27 @@ export interface BackendPluginConfig { // (undocumented) id: string; // (undocumented) - register(reg: BackendInitRegistry, options: TOptions): void; + register(reg: BackendRegistrationPoints, options: TOptions): void; } // @public (undocumented) -export interface BackendRegistrable { +export interface BackendRegistrationPoints { // (undocumented) - id: string; + registerExtensionPoint( + ref: ExtensionPoint, + impl: TExtensionPoint, + ): void; // (undocumented) - register(reg: BackendInitRegistry): void; + registerInit< + Deps extends { + [name in string]: unknown; + }, + >(options: { + deps: { + [name in keyof Deps]: ServiceRef | ExtensionPoint; + }; + init(deps: Deps): Promise; + }): void; } // @public (undocumented) @@ -83,12 +83,16 @@ export const configServiceRef: ServiceRef; // @public (undocumented) export function createBackendModule( config: BackendModuleConfig, -): (option: TOptions) => BackendRegistrable; +): undefined extends TOptions + ? (options?: TOptions) => BackendFeature + : (options: TOptions) => BackendFeature; // @public (undocumented) export function createBackendPlugin( config: BackendPluginConfig, -): (option: TOptions) => BackendRegistrable; +): undefined extends TOptions + ? (options?: TOptions) => BackendFeature + : (options: TOptions) => BackendFeature; // @public (undocumented) export function createExtensionPoint(options: { diff --git a/packages/backend-plugin-api/src/wiring/factories.test.ts b/packages/backend-plugin-api/src/wiring/factories.test.ts new file mode 100644 index 0000000000..6cfcdd06cc --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/factories.test.ts @@ -0,0 +1,89 @@ +/* + * 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 { + createBackendModule, + createBackendPlugin, + createExtensionPoint, +} from './factories'; + +describe('createExtensionPoint', () => { + it('should create an ExtensionPoint', () => { + const extensionPoint = createExtensionPoint({ id: 'x' }); + expect(extensionPoint).toBeDefined(); + expect(extensionPoint.id).toBe('x'); + expect(() => extensionPoint.T).toThrow(); + expect(String(extensionPoint)).toBe('extensionPoint{x}'); + }); +}); + +describe('createBackendPlugin', () => { + it('should create an BackendPlugin', () => { + const plugin = createBackendPlugin({ + id: 'x', + register(_reg, _options: { a: string }) {}, + }); + expect(plugin).toBeDefined(); + expect(plugin({ a: 'a' })).toBeDefined(); + expect(plugin({ a: 'a' }).id).toBe('x'); + // @ts-expect-error + expect(plugin()).toBeDefined(); + // @ts-expect-error + expect(plugin({ b: 'b' })).toBeDefined(); + }); + + it('should create plugins with optional options', () => { + const plugin = createBackendPlugin({ + id: 'x', + register(_reg, _options?: { a: string }) {}, + }); + expect(plugin).toBeDefined(); + expect(plugin({ a: 'a' })).toBeDefined(); + expect(plugin()).toBeDefined(); + // @ts-expect-error + expect(plugin({ b: 'b' })).toBeDefined(); + }); +}); + +describe('createBackendModule', () => { + it('should create an BackendModule', () => { + const mod = createBackendModule({ + pluginId: 'x', + moduleId: 'y', + register(_reg, _options: { a: string }) {}, + }); + expect(mod).toBeDefined(); + expect(mod({ a: 'a' })).toBeDefined(); + expect(mod({ a: 'a' }).id).toBe('x.y'); + // @ts-expect-error + expect(mod()).toBeDefined(); + // @ts-expect-error + expect(mod({ b: 'b' })).toBeDefined(); + }); + + it('should create modules with optional options', () => { + const mod = createBackendModule({ + pluginId: 'x', + moduleId: 'y', + register(_reg, _options?: { a: string }) {}, + }); + expect(mod).toBeDefined(); + expect(mod({ a: 'a' })).toBeDefined(); + expect(mod()).toBeDefined(); + // @ts-expect-error + expect(mod({ b: 'b' })).toBeDefined(); + }); +}); diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts new file mode 100644 index 0000000000..68f13f6c30 --- /dev/null +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -0,0 +1,82 @@ +/* + * 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 { + BackendRegistrationPoints, + BackendFeature, + ExtensionPoint, +} from './types'; + +/** @public */ +export function createExtensionPoint(options: { + id: string; +}): ExtensionPoint { + return { + id: options.id, + get T(): T { + throw new Error(`tried to read ExtensionPoint.T of ${this}`); + }, + toString() { + return `extensionPoint{${options.id}}`; + }, + $$ref: 'extension-point', // TODO: declare + }; +} + +/** @public */ +export interface BackendPluginConfig { + id: string; + register(reg: BackendRegistrationPoints, options: TOptions): void; +} + +/** @public */ +export function createBackendPlugin( + config: BackendPluginConfig, +): undefined extends TOptions + ? (options?: TOptions) => BackendFeature + : (options: TOptions) => BackendFeature { + return (options?: TOptions) => ({ + id: config.id, + register(register: BackendRegistrationPoints) { + return config.register(register, options!); + }, + }); +} + +/** @public */ +export interface BackendModuleConfig { + pluginId: string; + moduleId: string; + register( + reg: Omit, + options: TOptions, + ): void; +} + +/** @public */ +export function createBackendModule( + config: BackendModuleConfig, +): undefined extends TOptions + ? (options?: TOptions) => BackendFeature + : (options: TOptions) => BackendFeature { + return (options?: TOptions) => ({ + id: `${config.pluginId}.${config.moduleId}`, + register(register: BackendRegistrationPoints) { + // TODO: Hide registerExtensionPoint + return config.register(register, options!); + }, + }); +} diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 9340dc8fa9..8f85edb2eb 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -14,5 +14,14 @@ * limitations under the License. */ -export type { BackendRegistrable } from './types'; -export * from './types'; +export type { BackendModuleConfig, BackendPluginConfig } from './factories'; +export { + createBackendModule, + createBackendPlugin, + createExtensionPoint, +} from './factories'; +export type { + BackendRegistrationPoints, + BackendFeature, + ExtensionPoint, +} from './types'; diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index 2b0bef16f7..cdb56ea2e4 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -36,78 +36,22 @@ export type ExtensionPoint = { }; /** @public */ -export function createExtensionPoint(options: { - id: string; -}): ExtensionPoint { - return { - id: options.id, - get T(): T { - throw new Error(`tried to read ExtensionPoint.T of ${this}`); - }, - toString() { - return `extensionPoint{${options.id}}`; - }, - $$ref: 'extension-point', // TODO: declare - }; -} - -/** @public */ -export interface BackendInitRegistry { +export interface BackendRegistrationPoints { registerExtensionPoint( - ref: ServiceRef, + ref: ExtensionPoint, impl: TExtensionPoint, ): void; registerInit(options: { - deps: { [name in keyof Deps]: ServiceRef }; - init: (deps: Deps) => Promise; + deps: { + [name in keyof Deps]: ServiceRef | ExtensionPoint; + }; + init(deps: Deps): Promise; }): void; } /** @public */ -export interface BackendRegistrable { +export interface BackendFeature { + // TODO(Rugvip): Try to get rid of the ID at this level, allowing for a feature to register multiple features as a bundle id: string; - register(reg: BackendInitRegistry): void; -} - -/** @public */ -export interface BackendPluginConfig { - id: string; - register(reg: BackendInitRegistry, options: TOptions): void; -} - -// TODO: Make option optional in the returned factory if they are indeed optional -/** @public */ -export function createBackendPlugin( - config: BackendPluginConfig, -): (option: TOptions) => BackendRegistrable { - return options => ({ - id: config.id, - register(register) { - return config.register(register, options); - }, - }); -} - -/** @public */ -export interface BackendModuleConfig { - pluginId: string; - moduleId: string; - register( - reg: Omit, - options: TOptions, - ): void; -} - -// TODO: Make option optional in the returned factory if they are indeed optional -/** @public */ -export function createBackendModule( - config: BackendModuleConfig, -): (option: TOptions) => BackendRegistrable { - return options => ({ - id: `${config.pluginId}.${config.moduleId}`, - register(register) { - // TODO: Hide registerExtensionPoint - return config.register(register, options); - }, - }); + register(reg: BackendRegistrationPoints): void; } diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index cba8953432..b8881e659d 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -3,7 +3,11 @@ > Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). ```ts +import { AnyServiceFactory } from '@backstage/backend-plugin-api'; +import { BackendFeature } from '@backstage/backend-plugin-api'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { Knex } from 'knex'; +import { ServiceRef } from '@backstage/backend-plugin-api'; // @public (undocumented) export function isDockerDisabledForTests(): boolean; @@ -15,6 +19,38 @@ export function setupRequestMockHandlers(worker: { resetHandlers: () => void; }): void; +// @alpha (undocumented) +export function startTestBackend< + TServices extends any[], + TExtensionPoints extends any[], +>(options: TestBackendOptions): Promise; + +// @alpha (undocumented) +export interface TestBackendOptions< + TServices extends any[], + TExtensionPoints extends any[], +> { + // (undocumented) + extensionPoints?: readonly [ + ...{ + [index in keyof TExtensionPoints]: [ + ExtensionPoint, + Partial, + ]; + }, + ]; + // (undocumented) + features?: BackendFeature[]; + // (undocumented) + services?: readonly [ + ...{ + [index in keyof TServices]: + | AnyServiceFactory + | [ServiceRef, Partial]; + }, + ]; +} + // @public export type TestDatabaseId = | 'POSTGRES_13' diff --git a/packages/backend-test-utils/package.json b/packages/backend-test-utils/package.json index c3ba763bd2..3b490b625d 100644 --- a/packages/backend-test-utils/package.json +++ b/packages/backend-test-utils/package.json @@ -8,7 +8,8 @@ "publishConfig": { "access": "public", "main": "dist/index.cjs.js", - "types": "dist/index.d.ts" + "types": "dist/index.d.ts", + "alphaTypes": "dist/index.alpha.d.ts" }, "backstage": { "role": "node-library" @@ -25,7 +26,7 @@ ], "license": "Apache-2.0", "scripts": { - "build": "backstage-cli package build", + "build": "backstage-cli package build --experimental-type-build", "lint": "backstage-cli package lint", "test": "backstage-cli package test", "prepack": "backstage-cli package prepack", @@ -35,6 +36,8 @@ }, "dependencies": { "@backstage/backend-common": "^0.15.0-next.0", + "@backstage/backend-app-api": "^0.1.1-next.0", + "@backstage/backend-plugin-api": "^0.1.1-next.0", "@backstage/cli": "^0.18.1-next.0", "@backstage/config": "^1.0.1", "better-sqlite3": "^7.5.0", @@ -49,6 +52,7 @@ "@backstage/cli": "^0.18.1-next.0" }, "files": [ - "dist" + "dist", + "alpha" ] } diff --git a/packages/backend-test-utils/src/index.ts b/packages/backend-test-utils/src/index.ts index 5fef4e6b55..ae937d2fc8 100644 --- a/packages/backend-test-utils/src/index.ts +++ b/packages/backend-test-utils/src/index.ts @@ -22,4 +22,5 @@ export * from './database'; export * from './msw'; +export * from './next'; export * from './util'; diff --git a/packages/backend-test-utils/src/next/index.ts b/packages/backend-test-utils/src/next/index.ts new file mode 100644 index 0000000000..9bb5431772 --- /dev/null +++ b/packages/backend-test-utils/src/next/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './wiring'; diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts new file mode 100644 index 0000000000..488a258388 --- /dev/null +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -0,0 +1,97 @@ +/* + * 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 { + createBackendModule, + createExtensionPoint, + createServiceFactory, + createServiceRef, +} from '@backstage/backend-plugin-api'; +import { startTestBackend } from './TestBackend'; + +describe('TestBackend', () => { + it('should get a type error if service implementation does not match', async () => { + type Obj = { a: string; b: string }; + const serviceRef = createServiceRef({ id: 'a' }); + const extensionPoint1 = createExtensionPoint({ id: 'b1' }); + const extensionPoint2 = createExtensionPoint({ id: 'b2' }); + const extensionPoint3 = createExtensionPoint({ id: 'b3' }); + const extensionPoint4 = createExtensionPoint({ id: 'b4' }); + const extensionPoint5 = createExtensionPoint({ id: 'b5' }); + await startTestBackend({ + services: [ + // @ts-expect-error + [extensionPoint1, { a: 'a' }], + [serviceRef, { a: 'a' }], + [serviceRef, { a: 'a', b: 'b' }], + // @ts-expect-error + [serviceRef, { c: 'c' }], + // @ts-expect-error + [serviceRef, { a: 'a', c: 'c' }], + // @ts-expect-error + [serviceRef, { a: 'a', b: 'b', c: 'c' }], + ], + extensionPoints: [ + // @ts-expect-error + [serviceRef, { a: 'a' }], + [extensionPoint1, { a: 'a' }], + [extensionPoint2, { a: 'a', b: 'b' }], + // @ts-expect-error + [extensionPoint3, { c: 'c' }], + // @ts-expect-error + [extensionPoint4, { a: 'a', c: 'c' }], + // @ts-expect-error + [extensionPoint5, { a: 'a', b: 'b', c: 'c' }], + ], + }); + expect(1).toBe(1); + }); + + it('should start the test backend', async () => { + const testRef = createServiceRef<(v: string) => void>({ id: 'test' }); + const testFn = jest.fn(); + + const sf = createServiceFactory({ + deps: {}, + service: testRef, + factory: async () => { + return async () => testFn; + }, + }); + + const testModule = createBackendModule({ + moduleId: 'test.module', + pluginId: 'test', + register(env) { + env.registerInit({ + deps: { + test: testRef, + }, + async init({ test }) { + test('winning'); + }, + }); + }, + }); + + await startTestBackend({ + services: [sf], + features: [testModule({})], + }); + + expect(testFn).toBeCalledWith('winning'); + }); +}); diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts new file mode 100644 index 0000000000..b9276fa9b9 --- /dev/null +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -0,0 +1,95 @@ +/* + * 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 { createSpecializedBackend } from '@backstage/backend-app-api'; +import { + AnyServiceFactory, + ServiceRef, + createServiceFactory, + BackendFeature, + ExtensionPoint, +} from '@backstage/backend-plugin-api'; + +/** @alpha */ +export interface TestBackendOptions< + TServices extends any[], + TExtensionPoints extends any[], +> { + services?: readonly [ + ...{ + [index in keyof TServices]: + | AnyServiceFactory + | [ServiceRef, Partial]; + }, + ]; + extensionPoints?: readonly [ + ...{ + [index in keyof TExtensionPoints]: [ + ExtensionPoint, + Partial, + ]; + }, + ]; + features?: BackendFeature[]; +} + +/** @alpha */ +export async function startTestBackend< + TServices extends any[], + TExtensionPoints extends any[], +>(options: TestBackendOptions): Promise { + const { + services = [], + extensionPoints = [], + features = [], + ...otherOptions + } = options; + + const factories = services.map(serviceDef => { + if (Array.isArray(serviceDef)) { + // if type is ExtensionPoint? + // do something differently? + return createServiceFactory({ + service: serviceDef[0], + deps: {}, + factory: async () => async () => serviceDef[1], + }); + } + return serviceDef as AnyServiceFactory; + }); + + const backend = createSpecializedBackend({ + ...otherOptions, + services: factories, + }); + + backend.add({ + id: `---test-extension-point-registrar`, + register(reg) { + for (const [ref, impl] of extensionPoints) { + reg.registerExtensionPoint(ref, impl); + } + + reg.registerInit({ deps: {}, async init() {} }); + }, + }); + + for (const feature of features) { + backend.add(feature); + } + + await backend.start(); +} diff --git a/packages/backend-test-utils/src/next/wiring/index.ts b/packages/backend-test-utils/src/next/wiring/index.ts new file mode 100644 index 0000000000..eb7b773e33 --- /dev/null +++ b/packages/backend-test-utils/src/next/wiring/index.ts @@ -0,0 +1,18 @@ +/* + * 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. + */ + +export { startTestBackend } from './TestBackend'; +export type { TestBackendOptions } from './TestBackend'; diff --git a/packages/cli/config/eslint-factory.js b/packages/cli/config/eslint-factory.js index e86146048e..6e2a510c4a 100644 --- a/packages/cli/config/eslint-factory.js +++ b/packages/cli/config/eslint-factory.js @@ -76,7 +76,7 @@ function createConfig(dir, extraConfig = {}) { ...parserOptions, }, ignorePatterns: [ - '.eslintrc.js', + '.eslintrc.*', '**/dist/**', '**/dist-types/**', ...(ignorePatterns ?? []), diff --git a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts index 3d4f83b05d..6fa46db7c9 100644 --- a/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts +++ b/packages/core-app-api/src/apis/implementations/IdentityApi/AppIdentityProxy.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { withLogCollector } from '@backstage//test-utils'; +import { withLogCollector } from '@backstage/test-utils'; import { AppIdentityProxy } from './AppIdentityProxy'; describe('AppIdentityProxy', () => { 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 70bc66bcdd..ef05fa50ee 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 @@ -104,6 +104,6 @@ async function main() { module.hot?.accept(); main().catch(error => { - console.error(`Backend failed to start up, ${error}`); + console.error('Backend failed to start up', error); process.exit(1); }); diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts index fa7b251780..da67a2f88f 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.test.ts @@ -14,10 +14,22 @@ * limitations under the License. */ -import Knex from 'knex'; +import Knex, { Knex as KnexType } from 'knex'; import { DatabaseKeyStore } from './DatabaseKeyStore'; import { DateTime } from 'luxon'; +function createDatabaseManager( + client: KnexType, + skipMigrations: boolean = false, +) { + return { + getClient: async () => client, + migrations: { + skip: skipMigrations, + }, + }; +} + function createDB() { const knex = Knex({ client: 'better-sqlite3', @@ -38,8 +50,10 @@ const keyBase = { describe('DatabaseKeyStore', () => { it('should store a key', async () => { - const database = createDB(); - const store = await DatabaseKeyStore.create({ database }); + const client = createDB(); + const store = await DatabaseKeyStore.create({ + database: createDatabaseManager(client), + }); const key = { kid: '123', @@ -59,8 +73,10 @@ describe('DatabaseKeyStore', () => { }); it('should remove stored keys', async () => { - const database = createDB(); - const store = await DatabaseKeyStore.create({ database }); + const client = createDB(); + const store = await DatabaseKeyStore.create({ + database: createDatabaseManager(client), + }); const key1 = { kid: '1', ...keyBase }; const key2 = { kid: '2', ...keyBase }; diff --git a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts index 6bae1f4412..8039837469 100644 --- a/plugins/auth-backend/src/identity/DatabaseKeyStore.ts +++ b/plugins/auth-backend/src/identity/DatabaseKeyStore.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { resolvePackagePath } from '@backstage/backend-common'; +import { + PluginDatabaseManager, + resolvePackagePath, +} from '@backstage/backend-common'; import { Knex } from 'knex'; import { DateTime } from 'luxon'; import { AnyJWK, KeyStore, StoredKey } from './types'; @@ -33,7 +36,7 @@ type Row = { }; type Options = { - database: Knex; + database: PluginDatabaseManager; }; const parseDate = (date: string | Date) => { @@ -54,29 +57,32 @@ const parseDate = (date: string | Date) => { export class DatabaseKeyStore implements KeyStore { static async create(options: Options): Promise { const { database } = options; + const client = await database.getClient(); - await database.migrate.latest({ - directory: migrationsDir, - }); + if (!database.migrations?.skip) { + await client.migrate.latest({ + directory: migrationsDir, + }); + } - return new DatabaseKeyStore(options); + return new DatabaseKeyStore(client); } - private readonly database: Knex; + private readonly client: Knex; - private constructor(options: Options) { - this.database = options.database; + private constructor(client: Knex) { + this.client = client; } async addKey(key: AnyJWK): Promise { - await this.database(TABLE).insert({ + await this.client(TABLE).insert({ kid: key.kid, key: JSON.stringify(key), }); } async listKeys(): Promise<{ items: StoredKey[] }> { - const rows = await this.database(TABLE).select(); + const rows = await this.client(TABLE).select(); return { items: rows.map(row => ({ @@ -87,6 +93,6 @@ export class DatabaseKeyStore implements KeyStore { } async removeKeys(kids: string[]): Promise { - await this.database(TABLE).delete().whereIn('kid', kids); + await this.client(TABLE).delete().whereIn('kid', kids); } } diff --git a/plugins/auth-backend/src/identity/KeyStores.ts b/plugins/auth-backend/src/identity/KeyStores.ts index 3d238adba9..e29b4b6fc4 100644 --- a/plugins/auth-backend/src/identity/KeyStores.ts +++ b/plugins/auth-backend/src/identity/KeyStores.ts @@ -53,9 +53,7 @@ export class KeyStores { throw new Error('This KeyStore provider requires a database'); } - return await DatabaseKeyStore.create({ - database: await database.getClient(), - }); + return await DatabaseKeyStore.create({ database }); } if (provider === 'memory') { diff --git a/plugins/catalog-backend/api-report.md b/plugins/catalog-backend/api-report.md index 22a7f8192c..55f2d114db 100644 --- a/plugins/catalog-backend/api-report.md +++ b/plugins/catalog-backend/api-report.md @@ -5,7 +5,7 @@ ```ts /// -import { BackendRegistrable } from '@backstage/backend-plugin-api'; +import { BackendFeature } from '@backstage/backend-plugin-api'; import { CatalogApi } from '@backstage/catalog-client'; import { CatalogEntityDocument } from '@backstage/plugin-catalog-common'; import { CatalogProcessor } from '@backstage/plugin-catalog-node'; @@ -224,7 +224,7 @@ export type CatalogPermissionRule = PermissionRule; // @alpha -export const catalogPlugin: (option: unknown) => BackendRegistrable; +export const catalogPlugin: (options?: unknown) => BackendFeature; // @public (undocumented) export interface CatalogProcessingEngine { diff --git a/plugins/catalog-backend/src/service/CatalogPlugin.ts b/plugins/catalog-backend/src/service/CatalogPlugin.ts index b82797ec8b..ed356df5a2 100644 --- a/plugins/catalog-backend/src/service/CatalogPlugin.ts +++ b/plugins/catalog-backend/src/service/CatalogPlugin.ts @@ -27,7 +27,7 @@ import { CatalogBuilder } from './CatalogBuilder'; import { CatalogProcessor, CatalogProcessingExtensionPoint, - catalogProcessingExtentionPoint, + catalogProcessingExtensionPoint, EntityProvider, } from '@backstage/plugin-catalog-node'; @@ -62,7 +62,7 @@ export const catalogPlugin = createBackendPlugin({ const processingExtensions = new CatalogExtensionPointImpl(); // plugins depending on this API will be initialized before this plugins init method is executed. env.registerExtensionPoint( - catalogProcessingExtentionPoint, + catalogProcessingExtensionPoint, processingExtensions, ); diff --git a/plugins/catalog-node/api-report.md b/plugins/catalog-node/api-report.md index 0449708bc3..46e3efef99 100644 --- a/plugins/catalog-node/api-report.md +++ b/plugins/catalog-node/api-report.md @@ -7,8 +7,8 @@ import { CompoundEntityRef } from '@backstage/catalog-model'; import { Entity } from '@backstage/catalog-model'; +import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { JsonValue } from '@backstage/types'; -import { ServiceRef } from '@backstage/backend-plugin-api'; // @alpha (undocumented) export interface CatalogProcessingExtensionPoint { @@ -19,7 +19,7 @@ export interface CatalogProcessingExtensionPoint { } // @alpha (undocumented) -export const catalogProcessingExtentionPoint: ServiceRef; +export const catalogProcessingExtensionPoint: ExtensionPoint; // @public (undocumented) export type CatalogProcessor = { diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 560d9d4db1..80fbd7630f 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createServiceRef } from '@backstage/backend-plugin-api'; +import { createExtensionPoint } from '@backstage/backend-plugin-api'; import { EntityProvider } from './api'; import { CatalogProcessor } from './api/processor'; @@ -28,7 +28,7 @@ export interface CatalogProcessingExtensionPoint { /** * @alpha */ -export const catalogProcessingExtentionPoint = - createServiceRef({ +export const catalogProcessingExtensionPoint = + createExtensionPoint({ id: 'catalog.processing', }); diff --git a/plugins/catalog-node/src/index.ts b/plugins/catalog-node/src/index.ts index fc7a1b1b67..02ae325a9a 100644 --- a/plugins/catalog-node/src/index.ts +++ b/plugins/catalog-node/src/index.ts @@ -21,6 +21,6 @@ */ export type { CatalogProcessingExtensionPoint } from './extensions'; -export { catalogProcessingExtentionPoint } from './extensions'; +export { catalogProcessingExtensionPoint } from './extensions'; export * from './api'; export * from './processing'; diff --git a/plugins/code-climate/api-report.md b/plugins/code-climate/api-report.md index b0cc3e1450..5ef53cf543 100644 --- a/plugins/code-climate/api-report.md +++ b/plugins/code-climate/api-report.md @@ -8,6 +8,7 @@ import { ApiRef } from '@backstage/core-plugin-api'; import { BackstagePlugin } from '@backstage/core-plugin-api'; import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { FetchApi } from '@backstage/core-plugin-api'; import { RouteRef } from '@backstage/core-plugin-api'; // Warning: (ae-missing-release-tag) "CodeClimateApi" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -74,7 +75,8 @@ export const mockData: CodeClimateData; // // @public (undocumented) export class ProductionCodeClimateApi implements CodeClimateApi { - constructor(discoveryApi: DiscoveryApi); + // Warning: (ae-forgotten-export) The symbol "Options" needs to be exported by the entry point index.d.ts + constructor(options: Options); // (undocumented) fetchAllData(options: { apiUrl: string; diff --git a/plugins/code-climate/src/api/production-api.ts b/plugins/code-climate/src/api/production-api.ts index 665d7e9f63..81ba6b9ad6 100644 --- a/plugins/code-climate/src/api/production-api.ts +++ b/plugins/code-climate/src/api/production-api.ts @@ -22,7 +22,7 @@ import { CodeClimateIssuesData, } from './code-climate-data'; import { CodeClimateApi } from './code-climate-api'; -import { DiscoveryApi } from '@backstage/core-plugin-api'; +import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'; import { Duration } from 'luxon'; import humanizeDuration from 'humanize-duration'; @@ -34,8 +34,19 @@ const codeSmellsQuery = `${basicIssuesOptions}&${categoriesFilter}=Complexity`; const duplicationQuery = `${basicIssuesOptions}&${categoriesFilter}=Duplication`; const otherIssuesQuery = `${basicIssuesOptions}&${categoriesFilter}=Bug%20Risk`; +type Options = { + discoveryApi: DiscoveryApi; + fetchApi: FetchApi; +}; + export class ProductionCodeClimateApi implements CodeClimateApi { - constructor(private readonly discoveryApi: DiscoveryApi) {} + private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; + + constructor(options: Options) { + this.discoveryApi = options.discoveryApi; + this.fetchApi = options.fetchApi; + } async fetchAllData(options: { apiUrl: string; @@ -44,7 +55,6 @@ export class ProductionCodeClimateApi implements CodeClimateApi { testReportID: string; }): Promise { const { apiUrl, repoID, snapshotID, testReportID } = options; - const [ maintainabilityResponse, testCoverageResponse, @@ -52,15 +62,19 @@ export class ProductionCodeClimateApi implements CodeClimateApi { duplicationResponse, otherIssuesResponse, ] = await Promise.all([ - await fetch(`${apiUrl}/repos/${repoID}/snapshots/${snapshotID}`), - await fetch(`${apiUrl}/repos/${repoID}/test_reports/${testReportID}`), - await fetch( + await this.fetchApi.fetch( + `${apiUrl}/repos/${repoID}/snapshots/${snapshotID}`, + ), + await this.fetchApi.fetch( + `${apiUrl}/repos/${repoID}/test_reports/${testReportID}`, + ), + await this.fetchApi.fetch( `${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${codeSmellsQuery}`, ), - await fetch( + await this.fetchApi.fetch( `${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${duplicationQuery}`, ), - await fetch( + await this.fetchApi.fetch( `${apiUrl}/repos/${repoID}/snapshots/${snapshotID}/issues?${otherIssuesQuery}`, ), ]); @@ -109,7 +123,7 @@ export class ProductionCodeClimateApi implements CodeClimateApi { 'proxy', )}/codeclimate/api`; - const repoResponse = await fetch(`${apiUrl}/repos/${repoID}`); + const repoResponse = await this.fetchApi.fetch(`${apiUrl}/repos/${repoID}`); if (!repoResponse.ok) { throw new Error('Failed fetching Code Climate info'); diff --git a/plugins/code-climate/src/plugin.ts b/plugins/code-climate/src/plugin.ts index dcf86f1e19..54502b6355 100644 --- a/plugins/code-climate/src/plugin.ts +++ b/plugins/code-climate/src/plugin.ts @@ -20,7 +20,7 @@ import { createPlugin, createRouteRef, discoveryApiRef, - identityApiRef, + fetchApiRef, createComponentExtension, } from '@backstage/core-plugin-api'; @@ -37,9 +37,10 @@ export const codeClimatePlugin = createPlugin({ api: codeClimateApiRef, deps: { discoveryApi: discoveryApiRef, - identityApi: identityApiRef, + fetchApi: fetchApiRef, }, - factory: ({ discoveryApi }) => new ProductionCodeClimateApi(discoveryApi), + factory: ({ discoveryApi, fetchApi }) => + new ProductionCodeClimateApi({ discoveryApi, fetchApi }), }), ], routes: { diff --git a/plugins/github-issues/package.json b/plugins/github-issues/package.json index 109c825994..2ddb8481c4 100644 --- a/plugins/github-issues/package.json +++ b/plugins/github-issues/package.json @@ -21,7 +21,6 @@ "prepack": "backstage-cli package prepack", "postpack": "backstage-cli package postpack" }, - "prettier": "@spotify/prettier-config", "dependencies": { "@backstage/catalog-model": "^1.0.3", "@backstage/core-components": "^0.11.0-next.2", @@ -44,7 +43,6 @@ "@backstage/core-app-api": "^1.0.5-next.0", "@backstage/dev-utils": "^1.0.5-next.1", "@backstage/test-utils": "^1.1.3-next.0", - "@spotify/prettier-config": "^14.0.0", "@testing-library/jest-dom": "^5.10.1", "@testing-library/react": "^12.1.3", "@testing-library/user-event": "^14.0.0", @@ -52,8 +50,7 @@ "@types/node": "*", "@types/react": "^16.13.1 || ^17.0.0", "cross-fetch": "^3.1.5", - "msw": "^0.44.0", - "prettier": "^2.7.1" + "msw": "^0.44.0" }, "files": [ "dist" diff --git a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx index 87419aec94..dd38f513be 100644 --- a/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx +++ b/plugins/graphiql/src/components/GraphiQLBrowser/GraphiQLBrowser.tsx @@ -22,7 +22,9 @@ import { GraphQLEndpoint } from '../../lib/api'; import { BackstageTheme } from '@backstage/theme'; import { Progress } from '@backstage/core-components'; -const GraphiQL = React.lazy(() => import('graphiql')); +const GraphiQL = React.lazy(() => + import('graphiql').then(m => ({ default: m.GraphiQL })), +); const useStyles = makeStyles(theme => ({ root: { diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 7c24bdc572..96a4d7b400 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -5,7 +5,7 @@ ```ts /// -import { BackendRegistrable } from '@backstage/backend-plugin-api'; +import { BackendFeature } from '@backstage/backend-plugin-api'; import { CatalogApi } from '@backstage/catalog-client'; import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; import { CatalogProcessorEmit } from '@backstage/plugin-catalog-backend'; @@ -566,7 +566,7 @@ export type RunCommandOptions = { }; // @alpha -export const scaffolderCatalogModule: (option: unknown) => BackendRegistrable; +export const scaffolderCatalogModule: (options?: unknown) => BackendFeature; // @public (undocumented) export class ScaffolderEntitiesProcessor implements CatalogProcessor { diff --git a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts index f07eb0f7ae..1ced3dd676 100644 --- a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts +++ b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts @@ -14,27 +14,19 @@ * limitations under the License. */ -import { BackendInitRegistry } from '@backstage/backend-plugin-api'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; import { ScaffolderEntitiesProcessor } from '../processor'; import { scaffolderCatalogModule } from './ScaffolderCatalogModule'; +import { startTestBackend } from '@backstage/backend-test-utils'; describe('ScaffolderCatalogModule', () => { - it('should register the extension point', () => { - // TODO(jhaals): clean this up and add test helpers for backend system. - const ext = scaffolderCatalogModule({}); - expect(ext.id).toBe('catalog.scaffolder.module'); - const registry: jest.Mocked = { - registerInit: jest.fn(), - } as any; - ext.register(registry); - - const extensionPoint = { - addProcessor: jest.fn(), - }; - - registry.registerInit.mock.calls[0][0].init({ - catalogProcessingExtensionPoint: extensionPoint, + it('should register the extension point', async () => { + const extensionPoint = { addProcessor: jest.fn() }; + await startTestBackend({ + extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + features: [scaffolderCatalogModule({})], }); + expect(extensionPoint.addProcessor).toHaveBeenCalledWith( new ScaffolderEntitiesProcessor(), ); diff --git a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.ts b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.ts index bdce46a31a..0fb3c2e428 100644 --- a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.ts +++ b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.ts @@ -14,7 +14,7 @@ * limitations under the License. */ import { createBackendModule } from '@backstage/backend-plugin-api'; -import { catalogProcessingExtentionPoint } from '@backstage/plugin-catalog-node'; +import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; import { ScaffolderEntitiesProcessor } from '../processor'; /** @@ -27,12 +27,10 @@ export const scaffolderCatalogModule = createBackendModule({ register(env) { env.registerInit({ deps: { - catalogProcessingExtensionPoint: catalogProcessingExtentionPoint, + catalog: catalogProcessingExtensionPoint, }, - async init({ catalogProcessingExtensionPoint }) { - catalogProcessingExtensionPoint.addProcessor( - new ScaffolderEntitiesProcessor(), - ); + async init({ catalog }) { + catalog.addProcessor(new ScaffolderEntitiesProcessor()); }, }); }, diff --git a/plugins/scaffolder-backend/src/service/router.test.ts b/plugins/scaffolder-backend/src/service/router.test.ts index f545e57f85..f769038369 100644 --- a/plugins/scaffolder-backend/src/service/router.test.ts +++ b/plugins/scaffolder-backend/src/service/router.test.ts @@ -267,6 +267,57 @@ describe('createRouter', () => { ); }); + it('should not throw when an invalid authorization header is passed', async () => { + const broker = taskBroker.dispatch as jest.Mocked['dispatch']; + const mockToken = 'blob.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UifQ.blob'; + + await request(app) + .post('/v2/tasks') + .set('Authorization', `Bearer ${mockToken}`) + .send({ + templateRef: stringifyEntityRef({ + kind: 'template', + name: 'create-react-app-template', + }), + values: { + required: 'required-value', + }, + }); + expect(broker).toHaveBeenCalledWith( + expect.objectContaining({ + createdBy: undefined, + secrets: { + backstageToken: undefined, + }, + + spec: { + apiVersion: mockTemplate.apiVersion, + steps: mockTemplate.spec.steps.map((step, index) => ({ + ...step, + id: step.id ?? `step-${index + 1}`, + name: step.name ?? step.action, + })), + output: mockTemplate.spec.output ?? {}, + parameters: { + required: 'required-value', + }, + user: { + entity: undefined, + ref: undefined, + }, + templateInfo: { + entityRef: stringifyEntityRef({ + kind: 'Template', + namespace: 'Default', + name: mockTemplate.metadata?.name, + }), + baseUrl: 'https://dev.azure.com', + }, + }, + }), + ); + }); + it('should not decorate a user when no backstage auth is passed', async () => { const broker = taskBroker.dispatch as jest.Mocked['dispatch']; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 2f72004afe..2a8f15d967 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -146,7 +146,10 @@ export async function createRouter( '/v2/templates/:namespace/:kind/:name/parameter-schema', async (req, res) => { const { namespace, kind, name } = req.params; - const { token } = parseBearerToken(req.headers.authorization); + const { token } = parseBearerToken({ + header: req.headers.authorization, + logger, + }); const template = await findTemplate({ catalogApi: catalogClient, entityRef: { kind, namespace, name }, @@ -187,9 +190,10 @@ export async function createRouter( const { kind, namespace, name } = parseEntityRef(templateRef, { defaultKind: 'template', }); - const { token, entityRef: userEntityRef } = parseBearerToken( - req.headers.authorization, - ); + const { token, entityRef: userEntityRef } = parseBearerToken({ + header: req.headers.authorization, + logger, + }); const userEntity = userEntityRef ? await catalogClient.getEntityByRef(userEntityRef, { token }) @@ -389,7 +393,10 @@ export async function createRouter( throw new InputError('Input template is not a template'); } - const { token } = parseBearerToken(req.headers.authorization); + const { token } = parseBearerToken({ + header: req.headers.authorization, + logger, + }); for (const parameters of [template.spec.parameters ?? []].flat()) { const result = validate(body.values, parameters); @@ -440,7 +447,13 @@ export async function createRouter( return app; } -function parseBearerToken(header?: string): { +function parseBearerToken({ + header, + logger, +}: { + header?: string; + logger: Logger; +}): { token?: string; entityRef?: string; } { @@ -472,8 +485,12 @@ function parseBearerToken(header?: string): { throw new TypeError('Expected string sub claim'); } + // Check that it's a valid ref, otherwise this will throw. + parseEntityRef(sub); + return { entityRef: sub, token }; } catch (e) { - throw new InputError(`Invalid authorization header: ${stringifyError(e)}`); + logger.error(`Invalid authorization header: ${stringifyError(e)}`); + return {}; } } diff --git a/yarn.lock b/yarn.lock index 9bd862beb8..872925cd83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2249,10 +2249,10 @@ resolve-from "^5.0.0" semver "^5.4.1" -"@changesets/assemble-release-plan@^5.2.0": - version "5.2.0" - resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.0.tgz#35158dc9b496a4c108936ae8ad776ef855795ff6" - integrity sha512-ewY24PEbSec2eKX0+KM7eyENA2hUUp6s4LF9p/iBxTtc+TX2Xbx5rZnlLKZkc8tpuQ3PZbyjLFXWhd1PP6SjCg== +"@changesets/assemble-release-plan@^5.2.1": + version "5.2.1" + resolved "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.1.tgz#b66df8d4a5615d4d904b75f7b60faeb64eb1d506" + integrity sha512-d6ckasOWlKF9Mzs82jhl6TKSCgVvfLoUK1ERySrTg2TQJdrVUteZue6uEIYUTA7SgMu67UOSwol6R9yj1nTdjw== dependencies: "@babel/runtime" "^7.10.4" "@changesets/errors" "^0.1.4" @@ -2269,18 +2269,18 @@ "@changesets/types" "^5.1.0" "@changesets/cli@^2.14.0": - version "2.24.2" - resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.24.2.tgz#333ad412c821b582680fbc7f0d0596ebba442c2d" - integrity sha512-Bya7bnxF8Sz+O25M6kseAludVsCy5nXSW9u2Lbje/XbJTyU5q/xwIiXF9aTUzVi/4jyKoKoOasx7B1/z+NJLzg== + version "2.24.3" + resolved "https://registry.npmjs.org/@changesets/cli/-/cli-2.24.3.tgz#e6d8ab5d831d2249ca482955232a9a1c9ff02c21" + integrity sha512-okhRV+0WCQJa2Kmil/WvN5TK1o3+1JYSjrsGHqhjv+PYcDgDDgQ6I9J9OMBO9lfmNIpN7xSO80/BzxgvReO4Wg== dependencies: "@babel/runtime" "^7.10.4" "@changesets/apply-release-plan" "^6.0.4" - "@changesets/assemble-release-plan" "^5.2.0" + "@changesets/assemble-release-plan" "^5.2.1" "@changesets/changelog-git" "^0.1.12" "@changesets/config" "^2.1.1" "@changesets/errors" "^0.1.4" "@changesets/get-dependents-graph" "^1.3.3" - "@changesets/get-release-plan" "^3.0.13" + "@changesets/get-release-plan" "^3.0.14" "@changesets/git" "^1.4.1" "@changesets/logger" "^0.0.5" "@changesets/pre" "^1.0.12" @@ -2338,13 +2338,13 @@ fs-extra "^7.0.1" semver "^5.4.1" -"@changesets/get-release-plan@^3.0.13": - version "3.0.13" - resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.13.tgz#f5f7b67b798d1bf2d6e8e546a60c199dd09bfeaf" - integrity sha512-Zl/UN4FUzb5LwmzhO2STRijJT5nQCN4syPEs0p1HSIR+O2iVOzes+2yTLF2zGiOx8qPOsFx/GRSAvuhSzm+9ig== +"@changesets/get-release-plan@^3.0.14": + version "3.0.14" + resolved "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.14.tgz#b4423028a90c63feec12e22c48078f106f8d01f4" + integrity sha512-xzSfeyIOvUnbqMuQXVKTYUizreWQfICwoQpvEHoePVbERLocc1tPo5lzR7dmVCFcaA/DcnbP6mxyioeq+JuzSg== dependencies: "@babel/runtime" "^7.10.4" - "@changesets/assemble-release-plan" "^5.2.0" + "@changesets/assemble-release-plan" "^5.2.1" "@changesets/config" "^2.1.1" "@changesets/pre" "^1.0.12" "@changesets/read" "^0.5.7" @@ -4048,10 +4048,10 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.7": - version "0.3.13" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" - integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== +"@jridgewell/trace-mapping@^0.3.14": + version "0.3.15" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz#aba35c48a38d3fd84b37e66c9c0423f9744f9774" + integrity sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g== dependencies: "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" @@ -5449,15 +5449,15 @@ "@octokit/webhooks" "^10.0.0" "@octokit/auth-app@^4.0.0": - version "4.0.4" - resolved "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.4.tgz#e774da352e7c9d0648d5d0fdf0fb75cd6a16c2af" - integrity sha512-s3MK7M9e8TD/ih8lCBTrdZ74XPHMtHV7aycCKNBRQ2QJPdMwqx0mVbmLOIuW4dCwMX7K243+JAvf52tryFHRdQ== + version "4.0.5" + resolved "https://registry.npmjs.org/@octokit/auth-app/-/auth-app-4.0.5.tgz#0e52752c37340ae8686617b7ce188e4cae6d7ba1" + integrity sha512-fCbi4L/egsP3p4p1SelOFORM/m/5KxROhHdcIW5Lb17DDdW61fGT8y3wGpfiSeYNuulwF5QIfzJ7tdgtHNAymA== dependencies: "@octokit/auth-oauth-app" "^5.0.0" "@octokit/auth-oauth-user" "^2.0.0" "@octokit/request" "^6.0.0" "@octokit/request-error" "^3.0.0" - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" "@types/lru-cache" "^5.1.0" deprecation "^2.3.1" lru-cache "^6.0.0" @@ -5517,11 +5517,11 @@ "@octokit/types" "^6.0.0" "@octokit/auth-token@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.0.tgz#6f22c5fc56445c496628488ba6810131558fa4a9" - integrity sha512-MDNFUBcJIptB9At7HiV7VCvU3NcL4GnfCQaP8C5lrxWrRPMJBnemYtehaKSOlaM7AYxeRyj9etenu8LVpSpVaQ== + version "3.0.1" + resolved "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.1.tgz#88bc2baf5d706cb258474e722a720a8365dff2ec" + integrity sha512-/USkK4cioY209wXRpund6HZzHo9GmjakpV9ycOkpMcMxMk7QVcVFVyCMtzvXYiHsB2crgDgrtNYSELYFBXhhaA== dependencies: - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" "@octokit/auth-unauthenticated@^3.0.0": version "3.0.0" @@ -5544,15 +5544,15 @@ universal-user-agent "^6.0.0" "@octokit/core@^4.0.0": - version "4.0.2" - resolved "https://registry.npmjs.org/@octokit/core/-/core-4.0.2.tgz#4eaf9c5fd39913b541c5e31a2b8fdc3cf50480bc" - integrity sha512-vgVtE02EF9kXFsjmFoKFCwH1wDspPfDgopRbAlavkGuBJPWF+u5n0xgwP4obmdKNvLM+bB7MI7W31c2E13zgDQ== + version "4.0.5" + resolved "https://registry.npmjs.org/@octokit/core/-/core-4.0.5.tgz#589e68c0a35d2afdcd41dafceab072c2fbc6ab5f" + integrity sha512-4R3HeHTYVHCfzSAi0C6pbGXV8UDI5Rk+k3G7kLVNckswN9mvpOzW9oENfjfH3nEmzg8y3AmKmzs8Sg6pLCeOCA== dependencies: "@octokit/auth-token" "^3.0.0" - "@octokit/graphql" "^4.5.8" + "@octokit/graphql" "^5.0.0" "@octokit/request" "^6.0.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" + "@octokit/request-error" "^3.0.0" + "@octokit/types" "^7.0.0" before-after-hook "^2.2.0" universal-user-agent "^6.0.0" @@ -5570,23 +5570,23 @@ universal-user-agent "^6.0.0" "@octokit/endpoint@^6.0.1": - version "6.0.3" - resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.3.tgz#dd09b599662d7e1b66374a177ab620d8cdf73487" - integrity sha512-Y900+r0gIz+cWp6ytnkibbD95ucEzDSKzlEnaWS52hbCDNcCJYO5mRmWW7HRAnDc7am+N/5Lnd8MppSaTYx1Yg== - dependencies: - "@octokit/types" "^5.0.0" - is-plain-object "^3.0.0" - universal-user-agent "^5.0.0" - -"@octokit/endpoint@^7.0.0": - version "7.0.0" - resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.0.tgz#be758a1236d68d6bbb505e686dd50881c327a519" - integrity sha512-Kz/mIkOTjs9rV50hf/JK9pIDl4aGwAtT8pry6Rpy+hVXkAPhXanNQRxMoq6AeRgDCZR6t/A1zKniY2V1YhrzlQ== + version "6.0.12" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" + integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== dependencies: "@octokit/types" "^6.0.3" is-plain-object "^5.0.0" universal-user-agent "^6.0.0" +"@octokit/endpoint@^7.0.0": + version "7.0.1" + resolved "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.1.tgz#cb0d03e62e8762f3c80e52b025179de81899a823" + integrity sha512-/wTXAJwt0HzJ2IeE4kQXO+mBScfzyCkI0hMtkIaqyXd9zg76OpOfNQfHL9FlaxAV2RsNiOXZibVWloy8EexENg== + dependencies: + "@octokit/types" "^7.0.0" + is-plain-object "^5.0.0" + universal-user-agent "^6.0.0" + "@octokit/graphql@^4.5.8": version "4.8.0" resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" @@ -5597,12 +5597,12 @@ universal-user-agent "^6.0.0" "@octokit/graphql@^5.0.0": - version "5.0.0" - resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.0.tgz#2cc6eb3bf8e0278656df1a7d0ca0d7591599e3b3" - integrity sha512-1ZZ8tX4lUEcLPvHagfIVu5S2xpHYXAmgN0+95eAOPoaVPzCfUXJtA5vASafcpWcO86ze0Pzn30TAx72aB2aguQ== + version "5.0.1" + resolved "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.1.tgz#a06982514ad131fb6fbb9da968653b2233fade9b" + integrity sha512-sxmnewSwAixkP1TrLdE6yRG53eEhHhDTYUykUwdV9x8f91WcbhunIHk9x1PZLALdBZKRPUO2HRcm4kezZ79HoA== dependencies: "@octokit/request" "^6.0.0" - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" universal-user-agent "^6.0.0" "@octokit/oauth-app@^4.0.4", "@octokit/oauth-app@^4.0.6": @@ -5659,20 +5659,25 @@ resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-11.2.0.tgz#b38d7fc3736d52a1e96b230c1ccd4a58a2f400a6" integrity sha512-PBsVO+15KSlGmiI8QAzaqvsNlZlrDlyAJYcrXBCvVUxCp7VnXjkwPoFHgjEJXx3WF9BAwkA6nfCUA7i9sODzKA== +"@octokit/openapi-types@^12.11.0": + version "12.11.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz#da5638d64f2b919bca89ce6602d059f1b52d3ef0" + integrity sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ== + "@octokit/openapi-types@^12.4.0": version "12.4.0" resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.4.0.tgz#fd8bf5db72bd566c5ba2cb76754512a9ebe66e71" integrity sha512-Npcb7Pv30b33U04jvcD7l75yLU0mxhuX2Xqrn51YyZ5WTkF04bpbxLaZ6GcaTqu03WZQHoO/Gbfp95NGRueDUA== -"@octokit/openapi-types@^12.7.0": - version "12.8.0" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.8.0.tgz#f4708cf948724d6e8f7d878cfd91584c1c5c0523" - integrity sha512-ydcKLs2KKcxlhpdWLzJxEBDEk/U5MUeqtqkXlrtAUXXFPs6vLl1PEGghFC/BbpleosB7iXs0Z4P2DGe7ZT5ZNg== +"@octokit/openapi-types@^13.0.0": + version "13.0.1" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-13.0.1.tgz#f655810f0dc0547b771526fea171acffbc7bd4a8" + integrity sha512-40U39YoFBhJhmkAg6gbJnh9U8aueJwCuiTW0mXY2pNl9/+E7dUxXiMPOrIUGT12XqLinroaXYA3FUiw3BMeNfg== "@octokit/openapi-types@^7.3.2": - version "7.3.2" - resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.2.tgz#065ce49b338043ec7f741316ce06afd4d459d944" - integrity sha512-oJhK/yhl9Gt430OrZOzAl2wJqR0No9445vmZ9Ey8GjUZUpwuu/vmEFP0TDhDXdpGDoxD6/EIFHJEcY8nHXpDTA== + version "7.4.0" + resolved "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.4.0.tgz#07631899dc32b72a532178e27235c541f3c359f1" + integrity sha512-V2qNML1knHjrjTJcIIvhYZSTkvtSAoQpNEX8y0ykTJI8vOQPqIh0y6Jf9EU6c/y+v0c9+LeC1acwLQh1xo96MA== "@octokit/plugin-enterprise-rest@^6.0.1": version "6.0.1" @@ -5693,6 +5698,13 @@ dependencies: "@octokit/types" "^6.39.0" +"@octokit/plugin-paginate-rest@^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-4.0.0.tgz#859a168262b657d46a8f1243ded66c87cee964b9" + integrity sha512-g4GJMt/7VDmIMMdQenN6bmsmRoZca1c7IxOdF2yMiMwQYrE2bmmypGQeQSD5rsaffsFMCUS7Br4pMVZamareYA== + dependencies: + "@octokit/types" "^7.0.0" + "@octokit/plugin-request-log@^1.0.2": version "1.0.2" resolved "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.2.tgz#394d59ec734cd2f122431fbaf05099861ece3c44" @@ -5712,11 +5724,11 @@ deprecation "^2.3.1" "@octokit/plugin-rest-endpoint-methods@^6.0.0": - version "6.0.0" - resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.0.0.tgz#e4a55d83ec5a00e6b4d7a780f4ec9009095bff6f" - integrity sha512-9LkEvZB3WDuayEI381O5A/eM3QQioBZrwymQp5CUCNz9UMP/yZAIqBjcPhVJJFA3IRkKO1EARo98OePt9i0rkQ== + version "6.3.0" + resolved "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.3.0.tgz#81549334ce020169b84bd4a7fa2577e9d725d829" + integrity sha512-qEu2wn6E7hqluZwIEUnDxWROvKjov3zMIAi4H4d7cmKWNMeBprEXZzJe8pE5eStUYC1ysGhD0B7L6IeG1Rfb+g== dependencies: - "@octokit/types" "^6.39.0" + "@octokit/types" "^7.0.0" deprecation "^2.3.1" "@octokit/plugin-retry@^3.0.9": @@ -5745,11 +5757,11 @@ once "^1.4.0" "@octokit/request-error@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.0.tgz#f527d178f115a3b62d76ce4804dd5bdbc0270a81" - integrity sha512-WBtpzm9lR8z4IHIMtOqr6XwfkGvMOOILNLxsWvDwtzm/n7f5AWuqJTXQXdDtOvPfTDrH4TPhEvW2qMlR4JFA2w== + version "3.0.1" + resolved "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.1.tgz#3fd747913c06ab2195e52004a521889dadb4b295" + integrity sha512-ym4Bp0HTP7F3VFssV88WD1ZyCIRoE8H35pXSKwLeMizcdZAYc/t6N9X9Yr9n6t3aG9IH75XDnZ6UeZph0vHMWQ== dependencies: - "@octokit/types" "^6.0.3" + "@octokit/types" "^7.0.0" deprecation "^2.0.0" once "^1.4.0" @@ -5766,13 +5778,13 @@ universal-user-agent "^6.0.0" "@octokit/request@^6.0.0": - version "6.2.0" - resolved "https://registry.npmjs.org/@octokit/request/-/request-6.2.0.tgz#9c25606df84e6f2ccbcc2c58e1d35438e20b688b" - integrity sha512-7IAmHnaezZrgUqtRShMlByJK33MT9ZDnMRgZjnRrRV9a/jzzFwKGz0vxhFU6i7VMLraYcQ1qmcAOin37Kryq+Q== + version "6.2.1" + resolved "https://registry.npmjs.org/@octokit/request/-/request-6.2.1.tgz#3ceeb22dab09a29595d96594b6720fc14495cf4e" + integrity sha512-gYKRCia3cpajRzDSU+3pt1q2OcuC6PK8PmFIyxZDWCzRXRSIBH8jXjFJ8ZceoygBIm0KsEUg4x1+XcYBz7dHPQ== dependencies: "@octokit/endpoint" "^7.0.0" "@octokit/request-error" "^3.0.0" - "@octokit/types" "^6.16.1" + "@octokit/types" "^7.0.0" is-plain-object "^5.0.0" node-fetch "^2.6.7" universal-user-agent "^6.0.0" @@ -5788,29 +5800,36 @@ "@octokit/plugin-rest-endpoint-methods" "5.3.1" "@octokit/rest@^19.0.3": - version "19.0.3" - resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.3.tgz#b9a4e8dc8d53e030d611c053153ee6045f080f02" - integrity sha512-5arkTsnnRT7/sbI4fqgSJ35KiFaN7zQm0uQiQtivNQLI8RQx8EHwJCajcTUwmaCMNDg7tdCvqAnc7uvHHPxrtQ== + version "19.0.4" + resolved "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.4.tgz#fd8bed1cefffa486e9ae46a9dc608ce81bcfcbdd" + integrity sha512-LwG668+6lE8zlSYOfwPj4FxWdv/qFXYBpv79TWIQEpBLKA9D/IMcWsF/U9RGpA3YqMVDiTxpgVpEW3zTFfPFTA== dependencies: "@octokit/core" "^4.0.0" - "@octokit/plugin-paginate-rest" "^3.0.0" + "@octokit/plugin-paginate-rest" "^4.0.0" "@octokit/plugin-request-log" "^1.0.4" "@octokit/plugin-rest-endpoint-methods" "^6.0.0" -"@octokit/types@^5.0.0", "@octokit/types@^5.0.1": +"@octokit/types@^5.0.1": version "5.5.0" resolved "https://registry.npmjs.org/@octokit/types/-/types-5.5.0.tgz#e5f06e8db21246ca102aa28444cdb13ae17a139b" integrity sha512-UZ1pErDue6bZNjYOotCNveTXArOMZQFG6hKJfOnGnulVCMcVVi7YIIuuR4WfBhjo7zgpmzn/BkPDnUXtNx+PcQ== dependencies: "@types/node" ">= 8" -"@octokit/types@^6.0.0", "@octokit/types@^6.0.1", "@octokit/types@^6.0.3", "@octokit/types@^6.10.0", "@octokit/types@^6.12.2", "@octokit/types@^6.14.2", "@octokit/types@^6.16.1", "@octokit/types@^6.16.2", "@octokit/types@^6.8.2": +"@octokit/types@^6.0.0", "@octokit/types@^6.0.1", "@octokit/types@^6.10.0", "@octokit/types@^6.12.2", "@octokit/types@^6.14.2", "@octokit/types@^6.16.2", "@octokit/types@^6.8.2": version "6.16.4" resolved "https://registry.npmjs.org/@octokit/types/-/types-6.16.4.tgz#d24f5e1bacd2fe96d61854b5bda0e88cf8288dfe" integrity sha512-UxhWCdSzloULfUyamfOg4dJxV9B+XjgrIZscI0VCbp4eNrjmorGEw+4qdwcpTsu6DIrm9tQsFQS2pK5QkqQ04A== dependencies: "@octokit/openapi-types" "^7.3.2" +"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.39.0": + version "6.41.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz#e58ef78d78596d2fb7df9c6259802464b5f84a04" + integrity sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg== + dependencies: + "@octokit/openapi-types" "^12.11.0" + "@octokit/types@^6.27.1": version "6.34.0" resolved "https://registry.npmjs.org/@octokit/types/-/types-6.34.0.tgz#c6021333334d1ecfb5d370a8798162ddf1ae8218" @@ -5825,12 +5844,12 @@ dependencies: "@octokit/openapi-types" "^12.4.0" -"@octokit/types@^6.39.0": - version "6.39.0" - resolved "https://registry.npmjs.org/@octokit/types/-/types-6.39.0.tgz#46ce28ca59a3d4bac0e487015949008302e78eee" - integrity sha512-Mq4N9sOAYCitTsBtDdRVrBE80lIrMBhL9Jbrw0d+j96BAzlq4V+GLHFJbHokEsVvO/9tQupQdoFdgVYhD2C8UQ== +"@octokit/types@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/@octokit/types/-/types-7.0.0.tgz#3ecee92edff53a93ecd75d6b9d6620574d2048ca" + integrity sha512-8uSDc66p6+wADn6lh6lA7I3ZTIapn7F/dfpsiDztVjEr6kkyKR3qPqa4lgEX92O/8iJoDeGcscKRXGAjCSR/zg== dependencies: - "@octokit/openapi-types" "^12.7.0" + "@octokit/openapi-types" "^13.0.0" "@octokit/webhooks-methods@^3.0.0": version "3.0.0" @@ -5981,17 +6000,17 @@ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= -"@react-hookz/deep-equal@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.2.tgz#4e8bdeda027379dcf8b62a42e5f75f0351b11b35" - integrity sha512-cM5kPFb6EFH5q52WzRxfRX9+8g5kq78McWOYs6e1seo+nK6NpfLupT5uOCIJp37jU8ayd4Su8ni3HRFTN2C2kg== +"@react-hookz/deep-equal@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@react-hookz/deep-equal/-/deep-equal-1.0.3.tgz#e044bca38c1612ea8c1596ef858ef7cfea49dd7a" + integrity sha512-lGZR5l3YRjzeIOHtJhiq96vQKrsq+9lsCyv+0fROMQeSNWtLLzX3R+psHNi6nsoP3XEhspiZ92nsiPmdNo8ztQ== "@react-hookz/web@^15.0.0": - version "15.0.1" - resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.0.1.tgz#a6e5460dd16e54ccc0b899e1eed4ae29e871060f" - integrity sha512-nvVLUsDFv3fpZcINoy3I4MeaX8+yoKU21m2Ey2g0VAVqOMp+0GBBC6OHkzT2lRa2fiPIVuJwlmboSKQt7segfQ== + version "15.1.0" + resolved "https://registry.npmjs.org/@react-hookz/web/-/web-15.1.0.tgz#62f7cedb98f345a1cdc7437673ea93dfb4d753d1" + integrity sha512-AsmqeZDg22JnpQS1hGIjLbue4LPmcsgyoPzgmKt6WDeqIUWFL20cgowiGBMFNLvL5Cc9XdusVY720S+CpLyT4Q== dependencies: - "@react-hookz/deep-equal" "^1.0.2" + "@react-hookz/deep-equal" "^1.0.3" "@rjsf/core@^3.2.1": version "3.2.1" @@ -7351,7 +7370,7 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@>= 8", "@types/node@>=12.12.47", "@types/node@>=13.7.0": +"@types/node@*", "@types/node@>=12.12.47", "@types/node@>=13.7.0": version "17.0.25" resolved "https://registry.npmjs.org/@types/node/-/node-17.0.25.tgz#527051f3c2f77aa52e5dc74e45a3da5fb2301448" integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w== @@ -7361,6 +7380,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.20.24.tgz#c37ac69cb2948afb4cef95f424fa0037971a9a5c" integrity sha512-yxDeaQIAJlMav7fH5AQqPH1u8YIuhYJXYBzxaQ4PifsU0GDO38MSdmEDeRlIxrKbC6NbEaaEHDanWb+y30U8SQ== +"@types/node@>= 8": + version "18.7.4" + resolved "https://registry.npmjs.org/@types/node/-/node-18.7.4.tgz#95baa50846ae112a7376869d49fec23b2506c69d" + integrity sha512-RzRcw8c0B8LzryWOR4Wj7YOTFXvdYKwvrb6xQQyuDfnlTxwYXGCV5RZ/TEbq5L5kn+w3rliHAUyRcG1RtbmTFg== + "@types/node@^10.1.0", "@types/node@^10.12.0": version "10.17.60" resolved "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -7382,9 +7406,9 @@ integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== "@types/node@^16.0.0", "@types/node@^16.11.26", "@types/node@^16.9.2": - version "16.11.47" - resolved "https://registry.npmjs.org/@types/node/-/node-16.11.47.tgz#efa9e3e0f72e7aa6a138055dace7437a83d9f91c" - integrity sha512-fpP+jk2zJ4VW66+wAMFoBJlx1bxmBKx4DUFf68UHgdGCOuyUTDlLWqsaNPJh7xhNDykyJ9eIzAygilP/4WoN8g== + version "16.11.48" + resolved "https://registry.npmjs.org/@types/node/-/node-16.11.48.tgz#22d386f32b24fb644940b606ed393b56be7d8686" + integrity sha512-Z9r9UWlNeNkYnxybm+1fc0jxUNjZqRekTAr1pG0qdXe9apT9yCiqk1c4VvKQJsFpnchU4+fLl25MabSLA2wxIw== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -7678,9 +7702,9 @@ integrity sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A== "@types/semver@^7.3.8": - version "7.3.11" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.11.tgz#7a84d3228f34e68d14955fc406f8e66fdbe9e65e" - integrity sha512-R9HhjC4aKx3jL0FLwU7x6qMTysTvLh7jesRslXmxgCOXZwyh5dsnmrPQQToMyess8D4U+8G9x9mBFZoC/1o/Tw== + version "7.3.12" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz#920447fdd78d76b19de0438b7f60df3c4a80bf1c" + integrity sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A== "@types/serve-handler@^6.1.0": version "6.1.1" @@ -9106,9 +9130,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.814.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1192.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1192.0.tgz#13fe38ec8dae3232f17d52b370e69daa9c7a0e9c" - integrity sha512-6uzrlG1Ow3qcOnL0+et+DBTGhYgJzgNydVvos1Eg01vPc/ZhxR7roZ3epZQcPmOR0thQuzzckTq7FBO6wzZA2w== + version "2.1194.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1194.0.tgz#6a820684fa3f58ea40caf90d302414a23df7c308" + integrity sha512-wbgib7r7sHPkZIhqSMduueKYqe+DrFyxsKnUKHj6hdNcRKqEeqzvKp4olWmFs/3z3qU8+g78kBXr9rujvko1ug== dependencies: buffer "4.9.2" events "1.1.1" @@ -11204,17 +11228,6 @@ cross-spawn@^5.1.0: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -12937,9 +12950,9 @@ eslint-plugin-import@^2.25.4: tsconfig-paths "^3.14.1" eslint-plugin-jest@^26.1.2: - version "26.8.2" - resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.8.2.tgz#42a1248a5ade2bc589eb0f9c4e0608dd89b18cf3" - integrity sha512-67oh0FKaku9y48OpLzL3uK9ckrgLb83Sp5gxxTbtOGDw9lq6D8jw/Psj/9CipkbK406I2M7mvx1q+pv/MdbvxA== + version "26.8.3" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-26.8.3.tgz#f5d9bb162636491c8f6f0cd2743fe67c86569338" + integrity sha512-2roWu1MkEiihQ/qEszPPoaoqVI1x2D8Jtadk5AmoXTdEeNVPMu01Dtz7jIuTOAmdW3L+tSkPZOtEtQroYJDt0A== dependencies: "@typescript-eslint/utils" "^5.10.0" @@ -13054,9 +13067,9 @@ eslint-webpack-plugin@^3.1.1: schema-utils "^4.0.0" eslint@^8.6.0: - version "8.21.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz#1940a68d7e0573cef6f50037addee295ff9be9ef" - integrity sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA== + version "8.22.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz#78fcb044196dfa7eef30a9d65944f6f980402c48" + integrity sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA== dependencies: "@eslint/eslintrc" "^1.3.0" "@humanwhocodes/config-array" "^0.10.4" @@ -13357,19 +13370,6 @@ execa@5.1.1, execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - execa@^6.1.0: version "6.1.0" resolved "https://registry.npmjs.org/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" @@ -14353,13 +14353,6 @@ get-stdin@^8.0.0: resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^5.0.0, get-stream@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" @@ -16073,13 +16066,6 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-plain-object@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928" - integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg== - dependencies: - isobject "^4.0.0" - is-plain-object@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" @@ -16175,11 +16161,6 @@ is-stream-ended@^0.1.4: resolved "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz#f50224e95e06bce0e356d440a4827cd35b267eda" integrity sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw== -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -16329,11 +16310,6 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isobject@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" - integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== - isomorphic-dompurify@^0.13.0: version "0.13.0" resolved "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-0.13.0.tgz#a4dde357e8531018a85ebb2dd56c4794b6739ba3" @@ -18244,11 +18220,6 @@ lz-string@^1.4.4: resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz#c0d8eaf36059f705796e1e344811cf4c498d3a26" integrity sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY= -macos-release@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" - integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== - magic-string@^0.25.7: version "0.25.7" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" @@ -19575,11 +19546,6 @@ neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.2: resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - nise@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/nise/-/nise-5.1.1.tgz#ac4237e0d785ecfcb83e20f389185975da5c31f3" @@ -19922,13 +19888,6 @@ npm-registry-fetch@^9.0.0: minizlib "^2.0.0" npm-package-arg "^8.0.0" -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -20065,7 +20024,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0, object.assign@^4.1.2: +object.assign@^4.1.0: version "4.1.2" resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -20075,6 +20034,16 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" +object.assign@^4.1.2: + version "4.1.3" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.3.tgz#d36b7700ddf0019abb6b1df1bb13f6445f79051f" + integrity sha512-ZFJnX3zltyjcYJL0RoCJuzb+11zWGyaDbjgxZbdV7rFEcHQuYxrZqhow67aA7xpes6LhojyFDaBKAFfogQrikA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + object.entries@^1.1.5: version "1.1.5" resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" @@ -20288,14 +20257,6 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-name@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" - integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== - dependencies: - macos-release "^2.2.0" - windows-release "^3.1.0" - os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -20331,7 +20292,7 @@ p-filter@^2.1.0: p-finally@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== p-is-promise@^3.0.0: version "3.0.0" @@ -20884,11 +20845,6 @@ path-is-inside@1.0.2, path-is-inside@^1.0.2: resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -21579,7 +21535,7 @@ prettier@^1.16.4, prettier@^1.19.1: resolved "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.2.1, prettier@^2.7.1: +prettier@^2.2.1: version "2.7.1" resolved "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -23290,9 +23246,9 @@ rollup-plugin-dts@^4.0.1: "@babel/code-frame" "^7.16.7" rollup-plugin-esbuild@^4.7.2: - version "4.9.1" - resolved "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-4.9.1.tgz#369d137e2b1542c8ee459495fd4f10de812666aa" - integrity sha512-qn/x7Wz9p3Xnva99qcb+nopH0d2VJwVnsxJTGEg+Sh2Z3tqQl33MhOwzekVo1YTKgv+yAmosjcBRJygMfGrtLw== + version "4.9.3" + resolved "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-4.9.3.tgz#8c62042bdda9f33d18b1c280914394e5a842dd53" + integrity sha512-bxfUNYTa9Tw/4kdFfT9gtidDtqXyRdCW11ctZM7D8houCCVqp5qHzQF7hhIr31rqMA0APbG47fgVbbCGXgM49Q== dependencies: "@rollup/pluginutils" "^4.1.1" debug "^4.3.3" @@ -23561,7 +23517,7 @@ semver-store@^0.3.0: resolved "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz#ce602ff07df37080ec9f4fb40b29576547befbe9" integrity sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -24626,11 +24582,6 @@ strip-bom@^4.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -25046,17 +24997,17 @@ terminal-link@^2.0.0: supports-hyperlinks "^2.0.0" terser-webpack-plugin@*, terser-webpack-plugin@^5.1.3: - version "5.3.3" - resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" - integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== + version "5.3.4" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.4.tgz#f4d31e265883d20fda3ca9c0fc6a53f173ae62e3" + integrity sha512-SmnkUhBxLDcBfTIeaq+ZqJXLVEyXxSaNcCeSezECdKjfkMrTTnPvapBILylYwyEvHFZAn2cJ8dtiXel5XnfOfQ== dependencies: - "@jridgewell/trace-mapping" "^0.3.7" + "@jridgewell/trace-mapping" "^0.3.14" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.0" - terser "^5.7.2" + terser "^5.14.1" -terser@^5.10.0, terser@^5.7.2: +terser@^5.10.0, terser@^5.14.1: version "5.14.2" resolved "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10" integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA== @@ -25356,7 +25307,7 @@ tr46@^2.1.0: tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== traverse@^0.6.6, traverse@~0.6.6: version "0.6.6" @@ -25889,13 +25840,6 @@ universal-github-app-jwt@^1.0.1: "@types/jsonwebtoken" "^8.3.3" jsonwebtoken "^8.5.1" -universal-user-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz#a3182aa758069bf0e79952570ca757de3579c1d9" - integrity sha512-B5TPtzZleXyPrUMKCpEHFmVhMN6EhmJYjG5PQna9s7mXeSqGTLap4OpqLl5FCEFUI3UBmllkETwKf/db66Y54Q== - dependencies: - os-name "^3.1.0" - universal-user-agent@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" @@ -26383,7 +26327,7 @@ webcrypto-core@^1.7.4: webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webidl-conversions@^5.0.0: version "5.0.0" @@ -26528,7 +26472,7 @@ whatwg-mimetype@^3.0.0: whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -26610,13 +26554,6 @@ window-size@^0.2.0: resolved "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= -windows-release@^3.1.0: - version "3.2.0" - resolved "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f" - integrity sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA== - dependencies: - execa "^1.0.0" - winston-transport@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz#6e7b0dd04d393171ed5e4e4905db265f7ab384fa" @@ -26681,7 +26618,7 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3"