Initial work on the backend/next setup for the catalog
Co-authored-by: Patrik Oldsberg <poldsberg@gmail.com> Co-authored-by: blam <ben@blam.sh> Co-authored-by: Johan Haals <johan.haals@gmail.com> Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
committed by
Patrik Oldsberg
parent
4ad817262c
commit
39b24c78fe
@@ -0,0 +1,15 @@
|
||||
## API Report File for "@backstage/backend-app-api"
|
||||
|
||||
> 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 { BackendRegistrable } from '@backstage/backend-plugin-api';
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "CreateBackendOptions" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-forgotten-export) The symbol "Backend" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "createBackend" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function createBackend(options?: CreateBackendOptions): Backend;
|
||||
```
|
||||
@@ -33,7 +33,9 @@
|
||||
"clean": "backstage-cli package clean",
|
||||
"start": "backstage-cli package start"
|
||||
},
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"@backstage/backend-plugin-api": "^0.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.17.2-next.0"
|
||||
},
|
||||
|
||||
@@ -20,4 +20,4 @@
|
||||
* @packageDocumentation
|
||||
*/
|
||||
|
||||
export {};
|
||||
export { createBackend } from './wiring/types';
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 { BackendRegistrable, ServiceRef } from '@backstage/backend-plugin-api';
|
||||
import { BackendRegisterInit, ApiHolder } from './types';
|
||||
|
||||
export class BackendInitializer {
|
||||
#started = false;
|
||||
#extensions = new Map<BackendRegistrable, unknown>();
|
||||
// #stops = [];
|
||||
#registerInits = new Array<BackendRegisterInit>();
|
||||
#apis = new Map<ServiceRef<unknown>, unknown>();
|
||||
#apiHolder: ApiHolder;
|
||||
|
||||
constructor(apiHolder: ApiHolder) {
|
||||
this.#apiHolder = apiHolder;
|
||||
}
|
||||
|
||||
async #getInitDeps(
|
||||
deps: { [name: string]: ServiceRef<unknown> },
|
||||
pluginId: string,
|
||||
) {
|
||||
return Object.fromEntries(
|
||||
await Promise.all(
|
||||
Object.entries(deps).map(async ([name, apiRef]) => [
|
||||
name,
|
||||
this.#apis.get(apiRef) ||
|
||||
(await this.#apiHolder.get(apiRef)!(pluginId)),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
add<TOptions>(extension: BackendRegistrable, options?: TOptions) {
|
||||
if (this.#started) {
|
||||
throw new Error(
|
||||
'extension can not be added after the backend has started',
|
||||
);
|
||||
}
|
||||
this.#extensions.set(extension, options);
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
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<ServiceRef<unknown>>();
|
||||
|
||||
let registerInit: BackendRegisterInit | undefined = undefined;
|
||||
|
||||
console.log('Registering', extension.id);
|
||||
extension.register({
|
||||
registerExtensionPoint: (api, impl) => {
|
||||
if (registerInit) {
|
||||
throw new Error('registerInitApi called after registerInit');
|
||||
}
|
||||
if (this.#apis.has(api)) {
|
||||
throw new Error(`API ${api.id} already registered`);
|
||||
}
|
||||
this.#apis.set(api, impl);
|
||||
provides.add(api);
|
||||
},
|
||||
registerInit: registerOptions => {
|
||||
if (registerInit) {
|
||||
throw new Error('registerInit must only be called once');
|
||||
}
|
||||
registerInit = {
|
||||
id: extension.id,
|
||||
provides,
|
||||
consumes: new Set(Object.values(registerOptions.deps)),
|
||||
deps: registerOptions.deps,
|
||||
init: registerOptions.init as BackendRegisterInit['init'],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
if (!registerInit) {
|
||||
throw new Error(
|
||||
`registerInit was not called by register in ${extension.id}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.#registerInits.push(registerInit);
|
||||
}
|
||||
|
||||
this.validateSetup();
|
||||
|
||||
const orderedRegisterResults = this.#resolveInitOrder(this.#registerInits);
|
||||
|
||||
for (const registerInit of orderedRegisterResults) {
|
||||
// TODO: DI
|
||||
const deps = await this.#getInitDeps(registerInit.deps, registerInit.id);
|
||||
await registerInit.init(deps);
|
||||
// Maybe return stop? or lifecycle API
|
||||
// this.#stops.push();
|
||||
}
|
||||
}
|
||||
|
||||
// async stop(): Promise<void> {
|
||||
// for (const stop of this.#stops) {
|
||||
// await stop.stop();
|
||||
// }
|
||||
// }
|
||||
|
||||
private validateSetup() {}
|
||||
|
||||
#resolveInitOrder(registerInits: Array<BackendRegisterInit>) {
|
||||
let registerInitsToOrder = registerInits.slice();
|
||||
const orderedRegisterInits = new Array<BackendRegisterInit>();
|
||||
|
||||
// TODO: Validate duplicates
|
||||
|
||||
while (registerInitsToOrder.length > 0) {
|
||||
const toRemove = new Set<unknown>();
|
||||
|
||||
for (const registerInit of registerInitsToOrder) {
|
||||
const unInitializedDependents = Array.from(
|
||||
registerInit.provides,
|
||||
// eslint-disable-next-line no-loop-func
|
||||
).filter(r =>
|
||||
registerInitsToOrder.some(
|
||||
init => init !== registerInit && init.consumes.has(r),
|
||||
),
|
||||
);
|
||||
|
||||
if (unInitializedDependents.length === 0) {
|
||||
orderedRegisterInits.push(registerInit);
|
||||
toRemove.add(registerInit);
|
||||
}
|
||||
}
|
||||
|
||||
registerInitsToOrder = registerInitsToOrder.filter(r => !toRemove.has(r));
|
||||
}
|
||||
return orderedRegisterInits;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 {
|
||||
BackendRegistrable,
|
||||
AnyServiceFactory,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { BackendInitializer } from './BackendInitializer';
|
||||
import { CoreApiRegistry } from './CoreApiRegistry';
|
||||
import { Backend } from './types';
|
||||
|
||||
export class BackstageBackend implements Backend {
|
||||
#coreApis: CoreApiRegistry;
|
||||
#initializer: BackendInitializer;
|
||||
|
||||
constructor(apiFactories: AnyServiceFactory[]) {
|
||||
this.#coreApis = new CoreApiRegistry(apiFactories);
|
||||
this.#initializer = new BackendInitializer(this.#coreApis);
|
||||
}
|
||||
|
||||
add(extension: BackendRegistrable): void {
|
||||
this.#initializer.add(extension);
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
await this.#initializer.start();
|
||||
}
|
||||
|
||||
// async stop(): Promise<void> {
|
||||
// await this.#initializer.stop();
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 {
|
||||
AnyServiceFactory,
|
||||
ServiceRef,
|
||||
FactoryFunc,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
|
||||
export class CoreApiRegistry {
|
||||
readonly #implementations: Map<string, Map<string, unknown>>;
|
||||
readonly #factories: Map<string, AnyServiceFactory>;
|
||||
|
||||
constructor(factories: AnyServiceFactory[]) {
|
||||
this.#factories = new Map(factories.map(f => [f.service.id, f]));
|
||||
this.#implementations = new Map();
|
||||
}
|
||||
|
||||
get<T>(ref: ServiceRef<T>): FactoryFunc<T> | undefined {
|
||||
const factory = this.#factories.get(ref.id);
|
||||
if (!factory) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return async (pluginId: string): Promise<T> => {
|
||||
if (this.#implementations.has(ref.id)) {
|
||||
if (this.#implementations.get(ref.id)!.has(pluginId)) {
|
||||
return this.#implementations.get(ref.id)!.get(pluginId) as T;
|
||||
}
|
||||
this.#implementations.set(ref.id, new Map<string, unknown>());
|
||||
} else {
|
||||
this.#implementations.set(ref.id, new Map());
|
||||
}
|
||||
|
||||
const factoryDeps = Object.fromEntries(
|
||||
Object.entries(factory.deps).map(([name, apiRef]) => [
|
||||
name,
|
||||
this.get(apiRef)!, // TODO: throw
|
||||
]),
|
||||
);
|
||||
|
||||
const factoryFunc = await factory.factory(factoryDeps);
|
||||
const implementation = await factoryFunc(pluginId);
|
||||
|
||||
this.#implementations.set(
|
||||
ref.id,
|
||||
this.#implementations.get(ref.id)!.set(pluginId, implementation),
|
||||
);
|
||||
|
||||
return implementation as T;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface BackendApp {
|
||||
add(registrable: BackendRegistrable): void;
|
||||
import {
|
||||
BackendRegistrable,
|
||||
AnyServiceFactory,
|
||||
ServiceRef,
|
||||
FactoryFunc,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { BackstageBackend } from './BackstageBackend';
|
||||
|
||||
export interface Backend {
|
||||
add(extension: BackendRegistrable): void;
|
||||
start(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface BackendRegisterInit {
|
||||
id: string;
|
||||
consumes: Set<ServiceRef<unknown>>;
|
||||
provides: Set<ServiceRef<unknown>>;
|
||||
deps: { [name: string]: ServiceRef<unknown> };
|
||||
init: (deps: { [name: string]: unknown }) => Promise<void>;
|
||||
}
|
||||
|
||||
interface CreateBackendOptions {
|
||||
apis: AnyServiceFactory[];
|
||||
}
|
||||
|
||||
export type ApiHolder = {
|
||||
get<T>(api: ServiceRef<T>): FactoryFunc<T> | undefined;
|
||||
};
|
||||
|
||||
export function createBackend(options?: CreateBackendOptions): Backend {
|
||||
return new BackstageBackend(options?.apis ?? []);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
"clean": "backstage-cli package clean",
|
||||
"start": "backstage-cli package start"
|
||||
},
|
||||
"dependencies": {},
|
||||
"dependencies": {
|
||||
"@backstage/config": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^0.17.2-next.0"
|
||||
},
|
||||
|
||||
@@ -21,3 +21,5 @@
|
||||
*/
|
||||
|
||||
export * from './wiring';
|
||||
export * from './services/system/types';
|
||||
export * from './services/definitions';
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 { Config } from '@backstage/config';
|
||||
import { createServiceRef } from '../system/types';
|
||||
|
||||
export const configApiRef = createServiceRef<Config>({
|
||||
id: 'core.config',
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { createServiceRef } from '../system/types';
|
||||
|
||||
export interface HttpRouterApi {
|
||||
get(path: string): void;
|
||||
}
|
||||
|
||||
export const httpRouterApiRef = createServiceRef<HttpRouterApi>({
|
||||
id: 'core.httpRouter',
|
||||
});
|
||||
+6
-25
@@ -14,31 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
interface Logger {
|
||||
log(message: string): void;
|
||||
child(fields: { [name: string]: string }): Logger;
|
||||
}
|
||||
|
||||
interface ConfigApi {
|
||||
getString(key: string): string;
|
||||
}
|
||||
|
||||
interface HttpRouterApi {
|
||||
get(path: string): void;
|
||||
}
|
||||
|
||||
export const loggerApiRef = createServiceRef<Logger>({
|
||||
id: 'core.logger',
|
||||
});
|
||||
|
||||
export const configApiRef = createServiceRef<ConfigApi>({
|
||||
id: 'core.config',
|
||||
});
|
||||
|
||||
export const httpRouterApiRef = createServiceRef<HttpRouterApi>({
|
||||
id: 'core.apiRouter',
|
||||
});
|
||||
|
||||
// export type PluginEnvironment = {
|
||||
// logger: Logger;
|
||||
// cache: PluginCacheManager;
|
||||
@@ -50,3 +25,9 @@ export const httpRouterApiRef = createServiceRef<HttpRouterApi>({
|
||||
// permissions: PermissionEvaluator | PermissionAuthorizer;
|
||||
// scheduler: PluginTaskScheduler;
|
||||
// };
|
||||
|
||||
export { configApiRef } from './configApiRef';
|
||||
export { httpRouterApiRef } from './httpRouterApiRef';
|
||||
export type { HttpRouterApi } from './httpRouterApiRef';
|
||||
export { loggerApiRef } from './loggerApiRef';
|
||||
export type { Logger } from './loggerApiRef';
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 { createServiceRef } from '../system/types';
|
||||
|
||||
export interface Logger {
|
||||
log(message: string): void;
|
||||
child(fields: { [name: string]: string }): Logger;
|
||||
}
|
||||
|
||||
export const loggerApiRef = createServiceRef<Logger>({
|
||||
id: 'core.logger',
|
||||
});
|
||||
@@ -14,17 +14,56 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ServiceRef<T> {
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Utility for getting the type of the service, using `typeof serviceRef.T`.
|
||||
* Attempting to actually read this value will result in an exception.
|
||||
*/
|
||||
T: T;
|
||||
|
||||
toString(): string;
|
||||
|
||||
$$ref: 'service';
|
||||
}
|
||||
|
||||
type TypesToServiceRef<T> = { [key in keyof T]: ServiceRef<T[key]> };
|
||||
type DepsToDepFactories<T> = {
|
||||
[key in keyof T]: (pluginId: string) => Promise<T[key]>;
|
||||
};
|
||||
|
||||
export type FactoryFunc<Impl> = (pluginId: string) => Promise<Impl>;
|
||||
|
||||
export type ServiceFactory<
|
||||
TApi,
|
||||
TImpl extends TApi,
|
||||
TDeps extends { [name in string]: unknown },
|
||||
> = {
|
||||
service: ServiceRef<TApi>;
|
||||
deps: TypesToServiceRef<TDeps>;
|
||||
factory(deps: DepsToDepFactories<TDeps>): Promise<FactoryFunc<TImpl>>;
|
||||
};
|
||||
|
||||
export type AnyServiceFactory = ServiceFactory<
|
||||
unknown,
|
||||
unknown,
|
||||
{ [key in string]: unknown }
|
||||
>;
|
||||
|
||||
export function createServiceRef<T>(options: { id: string }): ServiceRef<T> {
|
||||
return {
|
||||
id: options.id,
|
||||
get T(): T {
|
||||
throw Error('NO T');
|
||||
throw new Error(`tried to read ServiceRef.T of ${this}`);
|
||||
},
|
||||
toString() {
|
||||
return `serviceRef{${options.id}}`;
|
||||
},
|
||||
$$ref: 'service', // TODO: declare
|
||||
};
|
||||
|
||||
@@ -14,4 +14,5 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { BackendRegistrable } from './types';
|
||||
export type { BackendRegistrable } from './types';
|
||||
export * from './types';
|
||||
|
||||
@@ -14,9 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ServiceRef } from '../services/system/types';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export interface ExtensionPoint<T> {
|
||||
id: string;
|
||||
|
||||
/**
|
||||
* Utility for getting the type of the extension point, using `typeof
|
||||
* extensionPoint.T`. Attempting to actually read this value will result in an
|
||||
* exception.
|
||||
*/
|
||||
T: T;
|
||||
|
||||
toString(): string;
|
||||
|
||||
$$ref: 'extension-point';
|
||||
}
|
||||
|
||||
@@ -26,7 +42,10 @@ export function createExtensionPoint<T>(options: {
|
||||
return {
|
||||
id: options.id,
|
||||
get T(): T {
|
||||
throw Error('NO T');
|
||||
throw new Error(`tried to read ExtensionPoint.T of ${this}`);
|
||||
},
|
||||
toString() {
|
||||
return `extensionPoint{${options.id}}`;
|
||||
},
|
||||
$$ref: 'extension-point', // TODO: declare
|
||||
};
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
"build-image": "docker build ../.. -f Dockerfile --tag example-backend"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/backend-plugin-api": "^0.0.0",
|
||||
"@backstage/backend-app-api": "^0.0.0",
|
||||
"@backstage/backend-common": "^0.14.1-next.2",
|
||||
"@backstage/backend-tasks": "^0.3.3-next.2",
|
||||
"@backstage/catalog-client": "^1.0.4-next.1",
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 { createBackend } from '@backstage/backend-app-api';
|
||||
import {
|
||||
createBackendModule,
|
||||
createBackendPlugin,
|
||||
createServiceRef,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
// import { catalogPlugin } from '@backstage/plugin-catalog-backend';
|
||||
// import { scaffolderPlugin } from '@backstage/plugin-scaffolder-backend';
|
||||
|
||||
interface CatalogProcessor {
|
||||
process(): void;
|
||||
}
|
||||
|
||||
interface CatalogProcessingInitApi {
|
||||
addProcessor(processor: CatalogProcessor): void;
|
||||
}
|
||||
|
||||
export const catalogProcessingInitApiRef =
|
||||
createServiceRef<CatalogProcessingInitApi>({
|
||||
id: 'catalog.processing',
|
||||
});
|
||||
|
||||
class CatalogExtensionPointImpl implements CatalogProcessingInitApi {
|
||||
#processors = new Array<CatalogProcessor>();
|
||||
|
||||
addProcessor(processor: CatalogProcessor): void {
|
||||
this.#processors.push(processor);
|
||||
}
|
||||
|
||||
get processors() {
|
||||
return this.#processors;
|
||||
}
|
||||
}
|
||||
|
||||
export const catalogPlugin = createBackendPlugin({
|
||||
id: 'catalog',
|
||||
register(env) {
|
||||
const processingExtensions = new CatalogExtensionPointImpl();
|
||||
// plugins depending on this API will be initialized before this plugins init method is executed.
|
||||
env.registerExtensionPoint(
|
||||
catalogProcessingInitApiRef,
|
||||
processingExtensions,
|
||||
);
|
||||
|
||||
env.registerInit({
|
||||
deps: {
|
||||
// logger: loggerApiRef,
|
||||
},
|
||||
async init() {
|
||||
console.log('I HAZ', processingExtensions.processors[0].process());
|
||||
console.log('I AM le CATALOG!');
|
||||
// logger.log('HELLO!');
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const scaffolderCatalogExtension = createBackendModule({
|
||||
moduleId: 'boop',
|
||||
pluginId: 'catalog',
|
||||
register(env) {
|
||||
env.registerInit({
|
||||
deps: {
|
||||
catalogProcessingInitApi: catalogProcessingInitApiRef,
|
||||
},
|
||||
async init({ catalogProcessingInitApi }) {
|
||||
catalogProcessingInitApi.addProcessor({
|
||||
process() {
|
||||
console.log('Running scaffolder processor');
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const backend = createBackend({
|
||||
apis: [],
|
||||
});
|
||||
|
||||
// backend.add(scaffolderPlugin());
|
||||
backend.add(catalogPlugin({}));
|
||||
backend.add(scaffolderCatalogExtension({}));
|
||||
backend.start();
|
||||
@@ -1557,6 +1557,126 @@
|
||||
lodash "^4.17.21"
|
||||
uuid "^8.0.0"
|
||||
|
||||
"@backstage/cli@^0.17.2-next.0":
|
||||
version "0.17.2"
|
||||
resolved "https://registry.npmjs.org/@backstage/cli/-/cli-0.17.2.tgz#2387b8d24d8af4828b84baaa62e6b444ec4330e6"
|
||||
integrity sha512-stRJWmokD7SXnclZ1dsVfA1stUP4PQPkbi3GkwY1zM84y4M20dU+YHde7MrTILMPnhMY+16WdTdfbeqLfXOJrw==
|
||||
dependencies:
|
||||
"@backstage/cli-common" "^0.1.9"
|
||||
"@backstage/config" "^1.0.1"
|
||||
"@backstage/config-loader" "^1.1.2"
|
||||
"@backstage/errors" "^1.0.0"
|
||||
"@backstage/release-manifests" "^0.0.4"
|
||||
"@backstage/types" "^1.0.0"
|
||||
"@hot-loader/react-dom-v16" "npm:@hot-loader/react-dom@^16.0.2"
|
||||
"@hot-loader/react-dom-v17" "npm:@hot-loader/react-dom@^17.0.2"
|
||||
"@manypkg/get-packages" "^1.1.3"
|
||||
"@octokit/request" "^5.4.12"
|
||||
"@rollup/plugin-commonjs" "^22.0.0"
|
||||
"@rollup/plugin-json" "^4.1.0"
|
||||
"@rollup/plugin-node-resolve" "^13.0.0"
|
||||
"@rollup/plugin-yaml" "^3.1.0"
|
||||
"@spotify/eslint-config-base" "^13.0.0"
|
||||
"@spotify/eslint-config-react" "^13.0.0"
|
||||
"@spotify/eslint-config-typescript" "^13.0.0"
|
||||
"@sucrase/jest-plugin" "^2.1.1"
|
||||
"@sucrase/webpack-loader" "^2.0.0"
|
||||
"@svgr/plugin-jsx" "6.2.x"
|
||||
"@svgr/plugin-svgo" "6.2.x"
|
||||
"@svgr/rollup" "6.2.x"
|
||||
"@svgr/webpack" "6.2.x"
|
||||
"@types/webpack-env" "^1.15.2"
|
||||
"@typescript-eslint/eslint-plugin" "^5.9.0"
|
||||
"@typescript-eslint/parser" "^5.9.0"
|
||||
"@yarnpkg/lockfile" "^1.1.0"
|
||||
"@yarnpkg/parsers" "^3.0.0-rc.4"
|
||||
bfj "^7.0.2"
|
||||
buffer "^6.0.3"
|
||||
chalk "^4.0.0"
|
||||
chokidar "^3.3.1"
|
||||
commander "^9.1.0"
|
||||
css-loader "^6.5.1"
|
||||
diff "^5.0.0"
|
||||
esbuild "^0.14.10"
|
||||
esbuild-loader "^2.18.0"
|
||||
eslint "^8.6.0"
|
||||
eslint-config-prettier "^8.3.0"
|
||||
eslint-formatter-friendly "^7.0.0"
|
||||
eslint-plugin-deprecation "^1.3.2"
|
||||
eslint-plugin-import "^2.25.4"
|
||||
eslint-plugin-jest "^26.1.2"
|
||||
eslint-plugin-jsx-a11y "^6.5.1"
|
||||
eslint-plugin-monorepo "^0.3.2"
|
||||
eslint-plugin-react "^7.28.0"
|
||||
eslint-plugin-react-hooks "^4.3.0"
|
||||
eslint-webpack-plugin "^3.1.1"
|
||||
express "^4.17.1"
|
||||
fork-ts-checker-webpack-plugin "^7.0.0-alpha.8"
|
||||
fs-extra "10.1.0"
|
||||
glob "^7.1.7"
|
||||
global-agent "^3.0.0"
|
||||
handlebars "^4.7.3"
|
||||
html-webpack-plugin "^5.3.1"
|
||||
inquirer "^8.2.0"
|
||||
jest "^27.5.1"
|
||||
jest-css-modules "^2.1.0"
|
||||
jest-runtime "^27.5.1"
|
||||
jest-transform-yaml "^1.0.0"
|
||||
json-schema "^0.4.0"
|
||||
lodash "^4.17.21"
|
||||
mini-css-extract-plugin "^2.4.2"
|
||||
minimatch "5.1.0"
|
||||
node-fetch "^2.6.7"
|
||||
node-libs-browser "^2.2.1"
|
||||
npm-packlist "^5.0.0"
|
||||
ora "^5.3.0"
|
||||
postcss "^8.1.0"
|
||||
process "^0.11.10"
|
||||
react-dev-utils "^12.0.0-next.60"
|
||||
react-hot-loader "^4.13.0"
|
||||
recursive-readdir "^2.2.2"
|
||||
replace-in-file "^6.0.0"
|
||||
rollup "^2.60.2"
|
||||
rollup-plugin-dts "^4.0.1"
|
||||
rollup-plugin-esbuild "^4.7.2"
|
||||
rollup-plugin-postcss "^4.0.0"
|
||||
rollup-pluginutils "^2.8.2"
|
||||
run-script-webpack-plugin "^0.0.14"
|
||||
semver "^7.3.2"
|
||||
style-loader "^3.3.1"
|
||||
sucrase "^3.20.2"
|
||||
tar "^6.1.2"
|
||||
terser-webpack-plugin "^5.1.3"
|
||||
util "^0.12.3"
|
||||
webpack "^5.66.0"
|
||||
webpack-dev-server "^4.7.3"
|
||||
webpack-node-externals "^3.0.0"
|
||||
yaml "^1.10.0"
|
||||
yml-loader "^2.1.0"
|
||||
yn "^4.0.0"
|
||||
zod "^3.11.6"
|
||||
|
||||
"@backstage/config-loader@^1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/@backstage/config-loader/-/config-loader-1.1.2.tgz#72cb0d7b2647f5a646bb279360bc34732e06521f"
|
||||
integrity sha512-c5ZO7xDJn609DBIsYAWGE5kgh+7SPYUmG2ADtVX9SbXaql3VCafGlhc2hAZQa/O12W04qi3GgwGg0bqSFmx5uw==
|
||||
dependencies:
|
||||
"@backstage/cli-common" "^0.1.9"
|
||||
"@backstage/config" "^1.0.1"
|
||||
"@backstage/errors" "^1.0.0"
|
||||
"@backstage/types" "^1.0.0"
|
||||
"@types/json-schema" "^7.0.6"
|
||||
ajv "^8.10.0"
|
||||
chokidar "^3.5.2"
|
||||
fs-extra "10.1.0"
|
||||
json-schema "^0.4.0"
|
||||
json-schema-merge-allof "^0.8.1"
|
||||
json-schema-traverse "^1.0.0"
|
||||
node-fetch "^2.6.7"
|
||||
typescript-json-schema "^0.53.0"
|
||||
yaml "^1.9.2"
|
||||
yup "^0.32.9"
|
||||
|
||||
"@backstage/core-components@^0.9.0", "@backstage/core-components@^0.9.5":
|
||||
version "0.9.5"
|
||||
resolved "https://registry.npmjs.org/@backstage/core-components/-/core-components-0.9.5.tgz#5a0b34867aaee0549bfa67b39a69c09588fa3c7a"
|
||||
@@ -5555,7 +5675,7 @@
|
||||
dependencies:
|
||||
"@rollup/pluginutils" "^3.0.8"
|
||||
|
||||
"@rollup/plugin-node-resolve@^13.0.6":
|
||||
"@rollup/plugin-node-resolve@^13.0.0", "@rollup/plugin-node-resolve@^13.0.6":
|
||||
version "13.3.0"
|
||||
resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.3.0.tgz#da1c5c5ce8316cef96a2f823d111c1e4e498801c"
|
||||
integrity sha512-Lus8rbUo1eEcnS4yTFKLZrVumLPY+YayBdWXgFSHYhTT2iJbMhoaaBL3xl5NCdeRytErGr8tZ0L71BMRmnlwSw==
|
||||
@@ -20504,6 +20624,11 @@ path-case@^3.0.4:
|
||||
dot-case "^3.0.4"
|
||||
tslib "^2.0.3"
|
||||
|
||||
path-equal@1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.1.2.tgz#260e7c449c4c2022f68cc5fa6e617e892858250d"
|
||||
integrity sha512-p5kxPPwCdbf5AdXzT1bUBJomhgBlEjRBavYNr1XUpMFIE4Hnf2roueCMXudZK5tnaAu1tTmp3GPzqwJK45IHEA==
|
||||
|
||||
path-equal@^1.1.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmjs.org/path-equal/-/path-equal-1.2.2.tgz#fa2997f0a829de22ec8f5f86461ca5590d49b832"
|
||||
@@ -23028,6 +23153,11 @@ run-parallel@^1.1.9:
|
||||
resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
|
||||
integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
|
||||
|
||||
run-script-webpack-plugin@^0.0.14:
|
||||
version "0.0.14"
|
||||
resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.0.14.tgz#fe2362b32c1dab7a8af7a6f1246fc043690cedd7"
|
||||
integrity sha512-DXe6lzzEVXjBr/74zd4m4yOfmz5P6GMjzhQxDDsViOmwG7cap8UCE6RgD5rT7zf4wM83a+ToHnpB3v4efUv5IA==
|
||||
|
||||
run-script-webpack-plugin@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmjs.org/run-script-webpack-plugin/-/run-script-webpack-plugin-0.1.1.tgz#dad3114be32eb864d2160306e4d9c52a2c1cfd59"
|
||||
@@ -25311,6 +25441,20 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript-json-schema@^0.53.0:
|
||||
version "0.53.1"
|
||||
resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.53.1.tgz#9204547f3e145169b40928998366ff6d28b81d32"
|
||||
integrity sha512-Hg+RnOKUd38MOzC0rDft03a8xvwO+gCcj1F77smw2tCoZYQpFoLtrXWBGdvCX+REliko5WYel2kux17HPFqjLQ==
|
||||
dependencies:
|
||||
"@types/json-schema" "^7.0.9"
|
||||
"@types/node" "^16.9.2"
|
||||
glob "^7.1.7"
|
||||
path-equal "1.1.2"
|
||||
safe-stable-stringify "^2.2.0"
|
||||
ts-node "^10.2.1"
|
||||
typescript "~4.6.0"
|
||||
yargs "^17.1.1"
|
||||
|
||||
typescript-json-schema@^0.54.0:
|
||||
version "0.54.0"
|
||||
resolved "https://registry.npmjs.org/typescript-json-schema/-/typescript-json-schema-0.54.0.tgz#b3fc42ad90df6a0f6ab57571ebc8b4d41125df4f"
|
||||
|
||||
Reference in New Issue
Block a user