Kwirth DCEs

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.

What is a DCE?

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.

DCE package (back.js exports { create }) │ │ Kwirth calls create(host) ── ONCE ──► the instance │ │ ▼ │ kept in global.__kwirth_dce__[id] plugin ──── getDce('my-icons') ───────────────┤ provider ─── getDce('my-icons') ───────────────┤ the SAME object, every time homepage ─── getDce('my-icons') ───────────────┘

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.

The rules

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"]
install a consumer
Refused when its DCE is missing or too old. The message says which DCE and which version — before you wonder why the consumer does nothing.
uninstall a DCE
Refused while somebody requires it. The message names who.
update across a major
Refused while a consumer requires the old major: in semver, 1.x → 2.0 means this breaks.
a factory that fails
Does not take the core down. The DCE is marked failed with the cause, and a consumer asking for it gets that cause as an error — never an empty value.
load order
DCEs load before every other family — and the front end does the same before adding any plugin, theme, homepage or configuration UI to the page — so a consumer can ask for its DCE the moment it starts, on either side.
one per side
One instance in the Kwirth process and one in each browser page: the back end's object lives in the server and the front end's in the page. Within one side, everybody shares it — which is the guarantee that matters.
updating
Installing is hot; updating needs a restart: consumers already running keep the instance they were given. Kwirth tells you so.

Available DCEs

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.

🔢

Sample

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.

for trying out

Build your own DCE

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 dce

And 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 why

Scaffold 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"
  }
}

Ready to share some code?

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