docs: update extension config schema examples to new configSchema format

Switch all documentation examples from the deprecated
`config: { schema: { field: z => z.type() } }` pattern to the new
`configSchema: { field: z.type() }` format using zod v4 imports.
Also update catalog-graph README to use current blueprint APIs.

Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
Made-with: Cursor
This commit is contained in:
Patrik Oldsberg
2026-04-10 10:58:21 +02:00
parent 1ef7954725
commit 3218028048
6 changed files with 60 additions and 78 deletions
@@ -278,15 +278,15 @@ In addition to being able to access data passed through the input, you also have
With the `app-config.yaml` there is already the option to pass configuration to plugins or the app to e.g. define the `baseURL` of your app. For extensions this concept would be limiting as an extension can be independent of the plugin & initiated several times. Therefore we created a possibility to configure each extension individually through config. The extension config schema is created using the [`zod`](https://zod.dev/) library, which in addition to TypeScript type checking also provides runtime validation and coercion. If we continue with the example of the `navigationExtension` and now want it to contain a configurable title, we could make it available like the following:
```tsx
import { z } from 'zod';
const navigationExtension = createExtension({
// ...
namespace: 'app',
name: 'nav',
// [3]: Extension `id` will be `app/nav` following the extension naming pattern
config: {
schema: {
title: z => z.string().default('Sidebar Title'),
},
configSchema: {
title: z.string().default('Sidebar Title'),
},
factory({ config }) {
return [
@@ -321,12 +321,12 @@ In all examples so far we have defined the extension factory as a regular functi
For example, this is how we could define an extension where its output depends on the configuration:
```tsx
import { z } from 'zod';
const exampleExtension = createExtension({
// ...
config: {
schema: {
disableIcon: z.boolean().default(false),
},
configSchema: {
disableIcon: z.boolean().default(false),
},
output: [coreExtensionData.reactElement, iconDataRef.optional()],
*factory({ config }) {
@@ -31,12 +31,12 @@ Every extension blueprint also provides a `makeWithOverrides` method. It is usef
The following is an example of how one might use the blueprint `makeWithOverrides` method to create a new extension:
```tsx
import { z } from 'zod';
const myPageExtension = PageBlueprint.makeWithOverrides({
// This defines additional configuration options for the extension.
config: {
schema: {
layout: z => z.enum(['grid', 'rows']).default('grid'),
},
configSchema: {
layout: z.enum(['grid', 'rows']).default('grid'),
},
// This defines additional inputs for the extension.
inputs: {
@@ -118,10 +118,8 @@ export interface MyWidgetBlueprintParams {
export const MyWidgetBlueprint = createExtensionBlueprint({
kind: 'my-widget',
attachTo: { id: 'page:my-plugin', input: 'widgets' },
config: {
schema: {
title: z.string().optional(),
},
configSchema: {
title: z.string().optional(),
},
output: [coreExtensionData.reactElement],
factory(params: MyWidgetBlueprintParams, { config }) {
@@ -196,10 +194,8 @@ const widgetTitleRef = createExtensionDataRef<string>().with({
export const MyWidgetBlueprint = createExtensionBlueprint({
kind: 'my-widget',
attachTo: { id: 'page:my-plugin', input: 'widgets' },
config: {
schema: {
title: z.string().optional(),
},
configSchema: {
title: z.string().optional(),
},
output: [widgetTitleRef, coreExtensionData.reactElement],
factory(params: MyWidgetBlueprintParams, { config }) {
@@ -182,20 +182,18 @@ const myOverrideExtension = myExtension.override({
Overriding the configuration schema works very similarly to overriding the declared inputs. You can define new configuration fields that will be merged with the existing ones, but you can not re-declare existing fields. The following example shows how to override an extension and add a new configuration field:
```tsx
import { z } from 'zod';
const exampleExtension = createExtension({
config: {
schema: {
foo: z => z.string(),
},
configSchema: {
foo: z.string(),
},
// ...
});
const overrideExtension = exampleExtension.override({
config: {
schema: {
bar: z => z.string(),
},
configSchema: {
bar: z.string(),
},
factory(originalFactory, { config }) {
//
@@ -210,12 +208,12 @@ const overrideExtension = exampleExtension.override({
In all examples so far we have called the `originalFactory` callback without any arguments. It is however possible to override parts of the factory context for the original factory using the first parameter of the original factory. This can be useful if you want to override the provided configuration or change the inputs in some way. Note that if you are implementing a `factory` for a blueprint, the override factory context will instead be the second parameter of the original factory function. The following is an example of how to override the configuration for the original factory:
```tsx
import { z } from 'zod';
const exampleExtension = createExtension({
name: 'example',
config: {
schema: {
layout: z => z.enum(['grid', 'list']).optional(),
},
configSchema: {
layout: z.enum(['grid', 'list']).optional(),
},
output: [coreExtensionData.reactElement],
factory: ({ config }) => [
@@ -94,11 +94,11 @@ The extension ID of the work API will be the kind `api:` followed by the plugin
Here we will describe how to amend a utility API with the capability of having extension config, which is driven by [your app-config](../../conf/writing.md). You do this by giving an extension config schema to your API extension factory function. Let's refactor the example above to also accept configuration, which will require us to use the [override method of the blueprint](../architecture/23-extension-blueprints.md#creating-an-extension-from-a-blueprint-with-overrides).
```tsx title="in @internal/plugin-example"
import { z } from 'zod';
const exampleWorkApi = ApiBlueprint.makeWithOverrides({
config: {
schema: {
goSlow: z => z.boolean().default(false),
},
configSchema: {
goSlow: z.boolean().default(false),
},
factory(originalFactory, { config }) {
return originalFactory({