This example demonstrates how to write a complete custom JMAP capability from scratch and use it with a client.
widget-capability.ts — The capability definition (no server needed): type definitions, invocation class, factories, validation plugin, session schemas, and type registry augmentation.custom-capability.ts — Using the capability with a client (server-connected): registers the capability, builds a request, and inspects the resulting request body.custom-capability.ts)Create a .env file in the repo root or export these variables in your shell:
JMAP_BEARER_TOKEN=your-token
JMAP_HOSTNAME=api.fastmail.com
JMAP_LOG_LEVEL=info
Clone the jmap-kit repository, then from the repo root:
yarn tsx examples/custom-capability/custom-capability.ts
urn:example:jmap:widgetWidgetObject, request/response argument types using the standard BaseGet*/BaseSet* genericsWidgetInvocation extending Invocation<TArgs> with the Widget URIWidget.request.get(), Widget.request.set(), and their response counterpartswidgetNameLengthValidator checks that widget names don't exceed 100 characters in Widget/set create operationsWidgetCapability combining URI, invocations, validators, and schemasdeclare module for ServerCapabilityRegistry and AccountCapabilityRegistryWidgetCapability alongside EmailCapabilityWidget/get and Widget/set invocationsusing array includes the Widget URI and the method calls use Widget/get and Widget/setA CapabilityDefinition assembles:
uri — the capability identifierinvocations — factory collections keyed by data typevalidators — validation plugins for the capability's methodsschema — StandardSchema validators for session capability datadeclare module extends the global type registries so TypeScript knows about the custom capability's session data:
declare module "../../src/common/types.js" {
interface ServerCapabilityRegistry {
[WIDGET_CAPABILITY_URI]?: EmptyObject;
}
interface AccountCapabilityRegistry {
[WIDGET_CAPABILITY_URI]?: {
maxWidgetsPerAccount: number;
supportsColours: boolean;
};
}
}
EmailCapability and CoreCapability.using URIs, method call IDs, and run through the validation pipeline automatically.guide/custom-capabilities.md for the full guide on writing custom capabilities.