frontend-plugin-api: add explicit ApiRef plugin ownership
Add the new frontend ApiRef builder form while preserving compatibility with existing refs, and let frontend apps resolve API ownership through an explicit pluginId when provided. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Made-with: Cursor
This commit is contained in:
@@ -169,6 +169,7 @@ describe('createSpecializedApp', () => {
|
||||
"api": {
|
||||
"$$type": "@backstage/ApiRef",
|
||||
"id": "core.featureflags",
|
||||
"pluginId": "app",
|
||||
"toString": [Function],
|
||||
"version": "v1",
|
||||
},
|
||||
@@ -182,6 +183,7 @@ describe('createSpecializedApp', () => {
|
||||
"api": {
|
||||
"$$type": "@backstage/ApiRef",
|
||||
"id": "core.app-tree",
|
||||
"pluginId": "app",
|
||||
"toString": [Function],
|
||||
"version": "v1",
|
||||
},
|
||||
@@ -195,6 +197,7 @@ describe('createSpecializedApp', () => {
|
||||
"api": {
|
||||
"$$type": "@backstage/ApiRef",
|
||||
"id": "core.config",
|
||||
"pluginId": "app",
|
||||
"toString": [Function],
|
||||
"version": "v1",
|
||||
},
|
||||
@@ -208,6 +211,7 @@ describe('createSpecializedApp', () => {
|
||||
"api": {
|
||||
"$$type": "@backstage/ApiRef",
|
||||
"id": "core.route-resolution",
|
||||
"pluginId": "app",
|
||||
"toString": [Function],
|
||||
"version": "v1",
|
||||
},
|
||||
@@ -221,6 +225,7 @@ describe('createSpecializedApp', () => {
|
||||
"api": {
|
||||
"$$type": "@backstage/ApiRef",
|
||||
"id": "core.identity",
|
||||
"pluginId": "app",
|
||||
"toString": [Function],
|
||||
"version": "v1",
|
||||
},
|
||||
@@ -364,6 +369,54 @@ describe('createSpecializedApp', () => {
|
||||
expect(app.apis.get(testApiRef)).toEqual({ value: 'owner' });
|
||||
});
|
||||
|
||||
it('should select the API factory from an explicitly owned plugin on conflict', () => {
|
||||
const testApiRef = createApiRef<{ value: string }>().with({
|
||||
id: 'shared.api',
|
||||
pluginId: 'owner',
|
||||
});
|
||||
|
||||
const app = createSpecializedApp({
|
||||
features: [
|
||||
makeAppPlugin(),
|
||||
createFrontendPlugin({
|
||||
pluginId: 'other-before',
|
||||
extensions: [
|
||||
ApiBlueprint.make({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: testApiRef,
|
||||
deps: {},
|
||||
factory: () => ({ value: 'other' }),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
createFrontendPlugin({
|
||||
pluginId: 'owner',
|
||||
extensions: [
|
||||
ApiBlueprint.make({
|
||||
params: defineParams =>
|
||||
defineParams({
|
||||
api: testApiRef,
|
||||
deps: {},
|
||||
factory: () => ({ value: 'owner' }),
|
||||
}),
|
||||
}),
|
||||
],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
expect(app.errors).toEqual([
|
||||
expect.objectContaining({
|
||||
code: 'API_FACTORY_CONFLICT',
|
||||
message: expect.stringContaining("API 'shared.api'"),
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(app.apis.get(testApiRef)).toEqual({ value: 'owner' });
|
||||
});
|
||||
|
||||
it('should allow API overrides within the same plugin', () => {
|
||||
const testApiRef = createApiRef<{ value: string }>({ id: 'test.api' });
|
||||
|
||||
|
||||
@@ -401,7 +401,7 @@ function createApiFactories(options: {
|
||||
const apiFactory = apiNode.instance?.getData(ApiBlueprint.dataRefs.factory);
|
||||
if (apiFactory) {
|
||||
const apiRefId = apiFactory.api.id;
|
||||
const ownerId = getApiOwnerId(apiRefId);
|
||||
const ownerId = getApiOwnerId(apiFactory.api);
|
||||
const pluginId = apiNode.spec.plugin.pluginId ?? 'app';
|
||||
const existingFactory = factoriesById.get(apiRefId);
|
||||
|
||||
@@ -455,7 +455,12 @@ function createApiFactories(options: {
|
||||
|
||||
// TODO(Rugvip): It would be good if this was more explicit, but I think that
|
||||
// might need to wait for some future update for API factories.
|
||||
function getApiOwnerId(apiRefId: string): string {
|
||||
function getApiOwnerId(apiRef: { id: string; pluginId?: string }): string {
|
||||
if (apiRef.pluginId) {
|
||||
return apiRef.pluginId;
|
||||
}
|
||||
|
||||
const apiRefId = apiRef.id;
|
||||
const [prefix, ...rest] = apiRefId.split('.');
|
||||
if (!prefix) {
|
||||
return apiRefId;
|
||||
|
||||
Reference in New Issue
Block a user