diff --git a/packages/frontend-app-api/src/createExtensionInstance.ts b/packages/frontend-app-api/src/createExtensionInstance.ts
index a7c49d48cb..d767f21d58 100644
--- a/packages/frontend-app-api/src/createExtensionInstance.ts
+++ b/packages/frontend-app-api/src/createExtensionInstance.ts
@@ -54,9 +54,17 @@ export function createExtensionInstance(options: {
extension.factory({
source,
config: parsedConfig,
- bind: mapValues(extension.output, ref => {
- return (value: unknown) => extensionData.set(ref.id, value);
- }),
+ bind: namedOutputs => {
+ for (const [name, output] of Object.entries(namedOutputs)) {
+ const ref = extension.output[name];
+ if (!ref) {
+ throw new Error(
+ `Extension instance '${extension.id}' tried to bind unknown output '${name}'`,
+ );
+ }
+ extensionData.set(ref.id, output);
+ }
+ },
inputs: mapValues(
extension.inputs,
({ extensionData: pointData }, inputName) => {
diff --git a/packages/frontend-app-api/src/extensions/CoreRouter.tsx b/packages/frontend-app-api/src/extensions/CoreRouter.tsx
index f2a760d25e..05f84aba6d 100644
--- a/packages/frontend-app-api/src/extensions/CoreRouter.tsx
+++ b/packages/frontend-app-api/src/extensions/CoreRouter.tsx
@@ -47,10 +47,12 @@ export const CoreRouter = createExtension({
return element;
};
- bind.component(() => (
-
-
-
- ));
+ bind({
+ component: () => (
+
+
+
+ ),
+ });
},
});
diff --git a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts
index d59a7ab2c3..057addc4a8 100644
--- a/packages/frontend-plugin-api/src/extensions/createApiExtension.ts
+++ b/packages/frontend-plugin-api/src/extensions/createApiExtension.ts
@@ -63,9 +63,9 @@ export function createApiExtension<
},
factory({ bind, config, inputs }) {
if (typeof factory === 'function') {
- bind.api(factory({ config, inputs }));
+ bind({ api: factory({ config, inputs }) });
} else {
- bind.api(factory);
+ bind({ api: factory });
}
},
});
diff --git a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx
index e136f1bc2a..7f16a81e24 100644
--- a/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx
+++ b/packages/frontend-plugin-api/src/extensions/createPageExtension.tsx
@@ -82,17 +82,18 @@ export function createPageExtension<
.component({ config, inputs })
.then(element => ({ default: () => element })),
);
- bind.path(config.path);
- bind.component(() => (
-
-
-
-
-
- ));
- if (options.routeRef) {
- bind.routeRef!(options.routeRef);
- }
+
+ bind({
+ path: config.path,
+ component: () => (
+
+
+
+
+
+ ),
+ routeRef: options.routeRef,
+ });
},
});
}
diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts
index 69ff83dfe9..14b1fd2d50 100644
--- a/packages/frontend-plugin-api/src/wiring/createExtension.test.ts
+++ b/packages/frontend-plugin-api/src/wiring/createExtension.test.ts
@@ -25,21 +25,26 @@ describe('createExtension', () => {
id: 'test',
at: 'root',
output: {
- foo: coreExtensionData.title,
- foo2: stringData,
+ foo: stringData,
},
factory({ bind }) {
- // Make it work well with required and optional output
- // HOH - High Order Helper
bind({
foo: 'bar',
});
+ bind({
+ // @ts-expect-error
+ foo: 3,
+ });
+ bind({
+ // @ts-expect-error
+ bar: 'bar',
+ });
// @ts-expect-error
- bind.foo(3);
+ bind({});
// @ts-expect-error
- bind.foo();
+ bind();
// @ts-expect-error
- bind.bar('bar');
+ bind('bar');
},
});
expect(extension.id).toBe('test');
diff --git a/packages/frontend-plugin-api/src/wiring/createExtension.ts b/packages/frontend-plugin-api/src/wiring/createExtension.ts
index e7f673cd2f..1ef0d3c272 100644
--- a/packages/frontend-plugin-api/src/wiring/createExtension.ts
+++ b/packages/frontend-plugin-api/src/wiring/createExtension.ts
@@ -19,9 +19,9 @@ import { BackstagePlugin } from './createPlugin';
import { AnyExtensionDataMap, Extension } from './types';
/** @public */
-export type ExtensionDataBind = {
- [K in keyof TData]: (value: TData[K]['T']) => void;
-};
+export type ExtensionDataBind = (outputs: {
+ [K in keyof TOutput]: TOutput[K]['T'];
+}) => void;
/** @public */
export type ExtensionDataValue = {
@@ -30,23 +30,23 @@ export type ExtensionDataValue = {
/** @public */
export interface CreateExtensionOptions<
- TData extends AnyExtensionDataMap,
- TPoint extends Record,
+ TOutput extends AnyExtensionDataMap,
+ TInputs extends Record,
TConfig,
> {
id: string;
at: string;
disabled?: boolean;
- inputs?: TPoint;
- output: TData;
+ inputs?: TInputs;
+ output: TOutput;
configSchema?: PortableSchema;
factory(options: {
source?: BackstagePlugin;
- bind: ExtensionDataBind;
+ bind: ExtensionDataBind;
config: TConfig;
inputs: {
- [pointName in keyof TPoint]: ExtensionDataValue<
- TPoint[pointName]['extensionData']
+ [pointName in keyof TInputs]: ExtensionDataValue<
+ TInputs[pointName]['extensionData']
>[];
};
}): void;
@@ -54,14 +54,28 @@ export interface CreateExtensionOptions<
/** @public */
export function createExtension<
- TData extends AnyExtensionDataMap,
- TPoint extends Record,
+ TOutput extends AnyExtensionDataMap,
+ TInputs extends Record,
TConfig = never,
->(options: CreateExtensionOptions): Extension {
+>(
+ options: CreateExtensionOptions,
+): Extension {
return {
...options,
disabled: options.disabled ?? false,
$$type: 'extension',
inputs: options.inputs ?? {},
+ factory({ bind, config, inputs }) {
+ // TODO: Simplify this, but TS wouldn't infer the input type for some reason
+ return options.factory({
+ bind,
+ config,
+ inputs: inputs as {
+ [pointName in keyof TInputs]: ExtensionDataValue<
+ TInputs[pointName]['extensionData']
+ >[];
+ },
+ });
+ },
};
}
diff --git a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts
index 7ebcb62ceb..724dad5143 100644
--- a/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts
+++ b/packages/frontend-plugin-api/src/wiring/createPlugin.test.ts
@@ -33,7 +33,7 @@ const TechRadarPage = createExtension({
name: nameExtensionDataRef,
},
factory({ bind }) {
- bind.name('TechRadar');
+ bind({ name: 'TechRadar' });
},
});
@@ -47,7 +47,7 @@ const CatalogPage = createExtension({
z.object({ name: z.string().default('Catalog') }),
),
factory({ bind, config }) {
- bind.name(config.name);
+ bind({ name: config.name });
},
});
@@ -61,7 +61,7 @@ const TechDocsAddon = createExtension({
z.object({ name: z.string().default('TechDocsAddon') }),
),
factory({ bind, config }) {
- bind.name(config.name);
+ bind({ name: config.name });
},
});
@@ -79,7 +79,7 @@ const TechDocsPage = createExtension({
name: nameExtensionDataRef,
},
factory({ bind, inputs }) {
- bind.name(`TechDocs-${inputs.addons.map(n => n.name).join('-')}`);
+ bind({ name: `TechDocs-${inputs.addons.map(n => n.name).join('-')}` });
},
});
@@ -97,11 +97,12 @@ const outputExtension = createExtension({
component: coreExtensionData.reactComponent,
},
factory({ bind, inputs }) {
- bind.component(() =>
- React.createElement('span', {}, [
- `Names: ${inputs.names.map(n => n.name).join(', ')}`,
- ]),
- );
+ bind({
+ component: () =>
+ React.createElement('span', {}, [
+ `Names: ${inputs.names.map(n => n.name).join(', ')}`,
+ ]),
+ });
},
});