api-ref: keep plugin ownership metadata internal

Hide plugin ownership metadata from the public ApiRef type while preserving internal ownership resolution for the builder-based API ref flow.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
This commit is contained in:
Patrik Oldsberg
2026-03-17 09:34:48 +01:00
parent 76b89c7437
commit ccc6b25f87
6 changed files with 16 additions and 7 deletions
@@ -194,7 +194,6 @@ export type ApiHolder = {
export type ApiRef<T, TId extends string = string> = {
readonly $$type?: '@backstage/ApiRef';
readonly id: TId;
readonly pluginId?: string;
readonly T: T;
};
@@ -27,6 +27,8 @@ describe('ApiRef', () => {
});
it('should not accept pluginId with deprecated config form', () => {
expect(createApiRef<string>({ id: 'abc' }).id).toBe('abc');
// @ts-expect-error pluginId is only supported through .with(...)
createApiRef<string>({ id: 'abc', pluginId: 'test' });
});
@@ -45,9 +47,12 @@ describe('ApiRef', () => {
const ref = createApiRef<string>().with({ id: 'abc', pluginId: 'test' });
expect(ref.$$type).toBe('@backstage/ApiRef');
expect(ref.id).toBe('abc');
expect(ref.pluginId).toBe('test');
expect(String(ref)).toBe('apiRef{abc}');
expect(ref.T).toBeNull();
expect((ref as { pluginId?: string }).pluginId).toBe('test');
// @ts-expect-error pluginId is internal runtime metadata
expect(ref.pluginId).toBe('test');
});
it('should infer literal ids with builder pattern', () => {
@@ -22,7 +22,6 @@
export type ApiRef<T, TId extends string = string> = {
readonly $$type?: '@backstage/ApiRef';
readonly id: TId;
readonly pluginId?: string;
readonly T: T;
};