Some code is shared by several extensions and belongs to none of them — and does not belong in the Kwirth core either. A suite's icon set. A client for an external system. A cache. A dynamic core extension is where that code lives: Kwirth instantiates it once, and every extension that needs it gets the same object.
A DCE brings objects, not data and not screens. Its package exports a factory — not the object itself. When the DCE loads, Kwirth calls create() once, hands it a host (a logger, a scoped key-value store, secrets, the core's own libraries) and keeps what comes back in a registry. Any other extension asks for it by id.
The rule of thumb against the other families: if it produces data it is a provider; if it draws something the user opens it is a plugin; if it provides code or objects other extensions call, it is a DCE.
Two consumers of the same DCE hold the same object. That is the whole point: one client, one cache, one registry — downloaded once, instantiated once, and updated in one place instead of republishing every consumer.
A DCE is a dependency, and Kwirth treats it as one. A consumer declares what it needs in its package.json, with the minimum version, through the same requiresExtension every extension already has:
"requiresExtension": ["dce:my-icons:1.0.0"]
1.x → 2.0 means this breaks.The first DCEs are the ones that prove the type. Suites of paid extensions carry their own — that is what the type was made for.
A shared counter. Two consumers calling next() see 1 and 2: they hold the same instance. Two copies would each say 1. Install it to watch the machinery work before writing your own.
A DCE is a small package: a contract, a factory, and a build that bundles nothing of Kwirth's — its imports resolve against the libraries the core already publishes, which is what keeps the registry a single one.
import { IDceBack, IDceBackHost } from '@kwirthmagnify/kwirth-common-back'
const dce: IDceBack<IMyIcons> = {
create: async (host: IDceBackHost): Promise<IMyIcons> => {
host.logger.info('my-icons created') // written under the DCE's id
const seen = await host.configMaps.read('boots', 0) // a store scoped to THIS dce
await host.configMaps.write('boots', Number(seen) + 1)
return createMyIcons(host.id)
}
}
export default dceAnd on the consumer's side, wherever it needs it:
import { getDce } from '@kwirthmagnify/kwirth-common-back'
const icons = getDce<IMyIcons>('my-icons') // throws if it is not loaded — and says whyScaffold one with node tools/create-kwirth-dce.mjs --id my-icons, and point Kwirth at your build while you develop it, the same way as any other extension:
{
"dces": {
"my-icons": "../dces/my-icons/dist"
}
}The full reference — the host, the dependency rules, what happens on update and on failure, and the worked example — is in the documentation.
DCE docs → Sample source