frontend-plugin-api: per-field config schema with lazy JSON Schema

Replace the monolithic `createSchemaFromZod` approach with per-field
schema resolution via `createConfigSchema`. Each field is resolved
individually and eagerly validated for JSON Schema conversion support,
but the actual JSON Schema generation is deferred until first access.

`PortableSchema.schema` is now a lazy callable — it can still be
accessed as a property (backward compat, deprecated) or called as a
method returning `{ schema: JsonObject }` for the new API.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
This commit is contained in:
Patrik Oldsberg
2026-04-10 10:13:19 +02:00
parent 0d398f3271
commit 1f80e1a5a4
11 changed files with 309 additions and 167 deletions
@@ -40,7 +40,7 @@ import {
resolveExtensionDefinition,
} from '../../../frontend-plugin-api/src/wiring/resolveExtensionDefinition';
// eslint-disable-next-line @backstage/no-relative-monorepo-imports
import { createSchemaFromZod } from '../../../frontend-plugin-api/src/schema/createSchemaFromZod';
import { createConfigSchema } from '../../../frontend-plugin-api/src/schema/createPortableSchema';
import { TestApiRegistry, withLogCollector } from '@backstage/test-utils';
import { createErrorCollector } from '../wiring/createErrorCollector';
@@ -181,12 +181,10 @@ describe('instantiateAppNodeTree', () => {
test: testDataRef,
other: otherDataRef.optional(),
},
configSchema: createSchemaFromZod(z =>
z.object({
output: z.string().default('test'),
other: z.number().optional(),
}),
),
configSchema: createConfigSchema({
output: z => z.string().default('test'),
other: z => z.number().optional(),
}),
factory({ config }) {
return { test: config.output, other: config.other };
},