@sorb/core reference

When you finish this page you know the shapes every other Sorb™ package agrees on — tiers, the resolved token entry, the semantic-role contract, and the connector registry — and where each one is enforced in code. You need no setup to read this page; you only install @sorb/core directly if you are writing a connector or citing its typedefs from your own JSDoc.

npm install @sorb/core

In a normal app you never install this yourself — @sorb/seed, @sorb/juice and @sorb/leaf all depend on it already, and importing any of them pulls it in transitively.

Tiers

Sorb's token taxonomy has three tiers. TIERS lists them most-specific first; TIER_RANK gives each a number so the lowest rank wins when two tokens resolve to the same CSS custom property — a component-tier token always overrides a semantic or primitive one bound to the same variable.

import { TIERS, TIER_RANK } from "@sorb/core";

TIERS; // ['component', 'semantic', 'primitive']
TIER_RANK; // { component: 0, semantic: 1, primitive: 2 }

The capture annotator (@sorb/seed) and the Sorb plugin both rank candidate bindings against TIER_RANK — it is the single place that precedence is decided.

The resolved token shape

ResolvedToken is the one shape that must not drift between packages: the bindable, fully-resolved entry that Style Dictionary's sorb/resolved-map format emits, that the bridge serves at GET /tokens/resolved, and that the capture annotator and the plugin both consume.

/**
 * @typedef {Object} ResolvedToken
 * @property {string} id        Dotted token id, e.g. "button.primary.bg.default"
 * @property {string} cssVar    Emitted CSS custom property, e.g. "--button-primary-bg-default"
 * @property {string|number} value  Fully resolved value (no var() chains)
 * @property {Tier} tier        Taxonomy tier — drives precedence via TIER_RANK
 * @property {TokenType} type   DTCG $type
 */

Reference it from your own JSDoc without re-declaring it:

/** @param {import('@sorb/core').ResolvedToken[]} resolved */

ResolvedMap is just ResolvedToken[] — the shape of .sorb/resolved.json and the bridge's GET /tokens/resolved response body. The full set — including the capture-side shapes LayerNode, SorbAnnotation and StoryIndex — is in the types table below.

Semantic-role contract and the role-id semver rule

The framework target adapters (sorb/mantine-vars, sorb/mui-vars, sorb/mat-sys-vars, sorb/shadcn-theme, sorb/primevue-preset) don't emit against one specific token kit's names — they emit against a canonical set of role ids, and a kit maps its own token ids onto those roles.

import { DEFAULT_ROLE_IDS, ALL_ROLE_IDS, resolveRole } from "@sorb/core";

DEFAULT_ROLE_IDS.color; // ['color.surface', 'color.ink', 'color.brand', ...]
ALL_ROLE_IDS; // flat list across color / radius / shadow / typography

// A format resolves a role id through your kit's roleMap — identity when
// your kit already uses the canonical ids as its own token ids:
resolveRole("color.brand", options.roleMap); // -> your kit's token id

If your kit uses different names, pass options.roleMap (role id → your token id) to the format instead of forking it — see the per-format options shapes on the @sorb/seed reference.

This is a semver-load-bearing list. Adding a role id to DEFAULT_ROLE_IDS/ALL_ROLE_IDS is a minor bump. Renaming or removing one is a major bump for @sorb/core and @sorb/seed, because every format consumer resolves against this exact set.

Connector registry

Tokens move through Sorb along three pluggable axes, each with its own registry inside connectors:

AxisRegistryRegisterLook upDefault id
Source — where tokens + geometry come inconnectors.sourceregisterSourcegetSourceDEFAULT_SOURCE_ID ('storybook-dom')
Code source — where the running app livesconnectors.codeSourceregisterCodeSourcegetCodeSourceDEFAULT_CODE_SOURCE_ID ('local')
Target — how tokens bind into the appconnectors.targetregisterTargetgetTargetDEFAULT_TARGET_ID ('react-bootstrap')

@sorb/seed registers the default source connector, @sorb/juice the default code-source connector, and @sorb/leaf registers all seven target adapters as an import side effect.

import { registerTarget, getTarget, resolveConnectorIds } from "@sorb/core";

registerTarget({
  id: "my-target",
  emitFormat: "SORB_TOKENSET",
  expectPrefixes: ["my-"],
});

getTarget("my-target"); // -> the adapter you just registered
getTarget("does-not-exist"); // throws: Unknown target adapter: "does-not-exist"

resolveConnectorIds({});
// -> { source: 'storybook-dom', codeSource: 'local', target: 'react-bootstrap' }

registerTarget validates the adapter's shape before adding it — a missing/empty id, a missing emitFormat, or a non-array expectPrefixes throws immediately, so a typo fails at register time instead of silently at the first lookup. Re-registering an existing id overwrites it with a console.warn, not a throw, so tests and HMR can re-register safely. resolveConnectorIds fills in the three defaults for any key your sorb.config.json omits.

Exports

ExportKindDescriptionSource
TIERSvalueToken tiers, most-specific first.src/index.js:18
TIER_RANKvalueTier → rank (0 = most specific).src/index.js:24
DEFAULT_ROLE_IDSvalueThe canonical role-id list (T0 reference = the JJ kit's semantic tier).src/index.js:66
ALL_ROLE_IDSvalueFlat list of every canonical role id (all tiers), for iteration/validation.src/index.js:89
resolveRolefunctionResolve a role id to the kit's actual token id via an optional override map.src/index.js:102
DEFAULT_SOURCE_IDvalueDefault SOURCE connector id (registered by sorb-seed).src/index.js:107
DEFAULT_CODE_SOURCE_IDvalueDefault CODE-SOURCE connector id (registered by sorb-juice).src/index.js:110
DEFAULT_TARGET_IDvalueDefault TARGET adapter id (registered by sorb-leaf).src/index.js:113
connectorsvalueThe runtime connector registry — id → impl per axis.src/index.js:123
registerSourcefunctionRegister a SOURCE connector by its id.src/index.js:134
registerCodeSourcefunctionRegister a CODE-SOURCE connector by its id.src/index.js:144
registerTargetfunctionRegister a TARGET adapter by its id.src/index.js:158
getSourcefunctionLook up a registered SOURCE connector; throws on unknown id.src/index.js:181
getCodeSourcefunctionLook up a registered CODE-SOURCE connector; throws on unknown id.src/index.js:192
getTargetfunctionLook up a registered TARGET adapter; throws on unknown id.src/index.js:203
resolveConnectorIdsfunctionResolve the three connector ids from a config, falling back to the defaults when a key is absent (back-compat = today's behavior).src/index.js:215

TIERS

const TIERS = Object.freeze(['component', 'semantic', 'primitive'])

Token tiers, most-specific first. Binding precedence: component beats semantic beats primitive.

TIER_RANK

const TIER_RANK = Object.freeze({ component: 0, semantic: 1, primitive: 2 })

Tier → rank (0 = most specific). Lower wins when several tokens share a value.

resolveRole

function resolveRole(roleId, roleMap)

Resolve a role id to the kit's actual token id via an optional override map. A format calls resolveRole('color.brand', options.roleMap) → the kit's token id (identity when the kit uses canonical ids, i.e. the JJ reference).

ParameterTypeDescription
roleIdstringA canonical role id from ALL_ROLE_IDS.
[roleMap]Record<string,string>role-id → kit-token-id overrides.

Returns string: the kit token id to reference (var(--&lt;kebab&gt;)).

DEFAULT_SOURCE_ID

const DEFAULT_SOURCE_ID = 'storybook-dom'

Default SOURCE connector id (registered by sorb-seed). @type {string}

DEFAULT_CODE_SOURCE_ID

const DEFAULT_CODE_SOURCE_ID = 'local'

Default CODE-SOURCE connector id (registered by sorb-juice). @type {string}

DEFAULT_TARGET_ID

const DEFAULT_TARGET_ID = 'react-bootstrap'

Default TARGET adapter id (registered by sorb-leaf). @type {string}

connectors

const connectors = Object.freeze(

The runtime connector registry — id → impl per axis. The Maps are mutable by design so consumer packages register their defaults into them; the container itself is frozen so the axis set can't drift.

registerSource

function registerSource(conn)

Register a SOURCE connector by its id.

ParameterTypeDescription
connSourceConnector

Returns SourceConnector: the registered connector.

registerCodeSource

function registerCodeSource(conn)

Register a CODE-SOURCE connector by its id.

ParameterTypeDescription
connCodeSourceConnector

Returns CodeSourceConnector: the registered connector.

registerTarget

function registerTarget(adapter)

Register a TARGET adapter by its id. Minimal shape validation (T0b) — with seven+ adapters registering into one Map, a typo'd id or missing emitFormat would fail silently at query time; catch it at register time. Throws on a malformed adapter; console.warns (does not throw) on a duplicate-id overwrite so a legitimate re-register in tests/HMR still works.

ParameterTypeDescription
adapterTargetAdapter

Returns TargetAdapter: the registered adapter.

getSource

function getSource(id)

Look up a registered SOURCE connector; throws on unknown id.

ParameterTypeDescription
idstring

Returns SourceConnector.

getCodeSource

function getCodeSource(id)

Look up a registered CODE-SOURCE connector; throws on unknown id.

ParameterTypeDescription
idstring

Returns CodeSourceConnector.

getTarget

function getTarget(id)

Look up a registered TARGET adapter; throws on unknown id.

ParameterTypeDescription
idstring

Returns TargetAdapter.

resolveConnectorIds

function resolveConnectorIds(config = {})

Resolve the three connector ids from a config, falling back to the defaults when a key is absent (back-compat = today's behavior).

ParameterTypeDescription
[config]{ source?: string, codeSource?: string, target?: string }

Returns { source: string, codeSource: string, target: string: }

Types

JSDoc typedefs. Import them in your own JSDoc with import('@sorb/core').Name.

Tier

Which layer of the 3-tier DTCG taxonomy a token belongs to.

type Tier = 'primitive' | 'semantic' | 'component'

Source: src/types.js:10

TokenType

DTCG $type of the resolved token (extend as the taxonomy grows).

type TokenType = 'color' | 'dimension' | 'fontFamily' | 'fontWeight' | 'number' | 'string'

Source: src/types.js:15

TokenSet

A flat map of token name → value.

type TokenSet = Object.<string, string | number>

Source: src/types.js:20

ResolvedToken

One entry of the resolved bindable token map — the single contract produced by Style Dictionary (sorb/resolved-map) and consumed by the bridge, the capture annotator, and the plugin. This is THE shape that must not drift.

PropertyTypeDescription
idstringDotted token id, e.g. button.primary.bg.default.
cssVarstringThe emitted CSS custom property, e.g. --button-primary-bg-default.
valuestring | numberFully resolved value (no var() chains).
tierTierTaxonomy tier (drives binding precedence via TIER_RANK).
typeTokenTypeDTCG $type.

Source: src/types.js:25

ResolvedMap

The resolved map as served/written: .sorb/resolved.json.

type ResolvedMap = ResolvedToken[]

Source: src/types.js:37

RawValue

A captured CSS value plus the raw string it came from.

PropertyTypeDescription
rawstringThe raw CSS string captured from the DOM (e.g. rgb(15,101,239)).

Source: src/types.js:42

LayerNode

A node in a captured layer tree (Storybook story → Figma-insertable geometry). Produced by capture, annotated in place by the seed annotator, materialized by the plugin.

PropertyTypeDescription
typestringFigma-ish node type, e.g. FRAME, TEXT.
fills (optional)RawValue[]Fill paints (index 0 is the primary fill).
strokes (optional)RawValue[]Stroke paints.
cornerRadius (optional)numberCorner radius in px.
effects (optional){ color?: RawValue }[]Effects (shadows, etc.).
children (optional)LayerNode[]Child nodes.
sorb (optional)SorbAnnotationToken bindings attached by the annotator.

Source: src/types.js:48

SorbAnnotation

Token bindings the seed annotator stamps onto a matched LayerNode.

PropertyTypeDescription
tokensObject.<string, string>role (fill/stroke/cornerRadius/effectN) → bound token id.
candidatesObject.<string, string[]>role → all token ids whose value matched (the plugin offers these as a switch).

Source: src/types.js:62

StoryEntry

One story's entry in the capture index (.sorb/index.json).

PropertyTypeDescription
artifactstringRelative path to the captured artifact (*.sorb.json).

Source: src/types.js:71

StoryIndex

The capture index written to .sorb/index.json.

PropertyTypeDescription
storiesObject.<string, StoryEntry>storyId → entry.

Source: src/types.js:77

VariantSpec

Identifies a component variant by its dot-path prefix. e.g. "button.tertiary" covers all tokens whose id starts with "button.tertiary."

PropertyTypeDescription
componentIdstringTop-level component key, e.g. "button".
variantIdstringFull dot-path of the variant, e.g. "button.tertiary".
fromVariant (optional)stringDot-path of the source variant to clone from (addVariant only).
replacedBy (optional)stringDot-path that replaces this variant (deprecateVariant only).

Source: src/types.js:83

VariantChangeset

The result of a lifecycle action — what changed.

PropertyTypeDescription
action'add'|'deprecate'
variantIdstringThe variant that was added or deprecated.
tokenIdsstring[]All token ids affected (added or deprecated).
newVersionstringThe component set's new $version after the change.

Source: src/types.js:93

DesignUnit

A design unit to capture — one addressable thing a SourceConnector can turn into geometry (today's Storybook "story entry" is one). Opaque-ish: only id is guaranteed; connectors carry whatever extra metadata they need.

PropertyTypeDescription
idstringStable unit id (e.g. a Storybook story id).
name (optional)stringHuman-readable label.

Source: src/types.js:102

SourceConnector

SOURCE axis — where design tokens + geometry come IN. A real source pulls BOTH tokens and geometry from the tool (founder decision 2026-08-28).

PropertyTypeDescription
idstringRegistry key (default 'storybook-dom').
listUnits(config: Object) => Promise<DesignUnit[]>Discover the design units to capture.
captureGeometry(unit: DesignUnit, config: Object) => Promise<LayerNode>Capture one unit as a raw (un-annotated) LayerNode tree.
readTokens(config: Object) => Promise<TokenSet>Read the DTCG token set for this source.

Source: src/types.js:111

CodeSourceConnector

CODE-SOURCE axis — where the running app / codebase lives.

PropertyTypeDescription
idstringRegistry key (default 'local').
resolveAppUrl(config: Object) => Promise<string|null>Resolve the running app's URL (today = appUrl / localhost:5173).
resolveProjectRoot(config: Object) => stringResolve the project root dir (today = process.cwd()).
provision (optional)(config: Object) => Promise<void>Optional: clone/build a repo → hosted preview (future code sources).

Source: src/types.js:124

TargetAdapter

TARGET axis — how tokens bind into the running app (the component-compat seam).

PropertyTypeDescription
idstringRegistry key (default 'react-bootstrap').
emitFormatstringA Style-Dictionary format id (e.g. SORB_TOKENSET).
expectPrefixesstring[]Vocab-guard namespace(s), e.g. ['bs-'].
inject (optional)(tokens: TokenSet, config: Object) => voidOptional: bind tokens into non-React hosts (the sorbInit seam).
darkMode (optional)DarkModeConventionOptional: this target's dark-mode convention (real-dark-mode spec D1). Undefined ⇒ single-mode (no dark) — the target has no notion of a dark variant and mode-aware emit/inject should fall back to flat :root output.

Source: src/types.js:136

DarkModeConvention

How a TargetAdapter's host framework expresses light/dark mode. v1 only ships 'attribute' (Bootstrap 5.3's [data-bs-theme]); 'class' (Tailwind's .dark) and 'media' (OS-only, no manual override) are named here for forward-compat but not yet implemented by any shipped adapter — see real-dark-mode-implementation spec §3 "Deferred to phase 2".

PropertyTypeDescription
strategy'attribute'|'class'|'media'How the manual override is expressed. 'attribute' sets/reads a DOM attribute (e.g. data-bs-theme); 'class' toggles a class on documentElement; 'media' means OS-only, no manual override.
attribute (optional)stringThe attribute name for strategy: 'attribute' (e.g. 'data-bs-theme').
darkSelectorstringThe CSS selector matching the dark-mode override (e.g. '[data-bs-theme="dark"]').
lightSelector (optional)stringThe CSS selector matching an explicit light-mode override (e.g. '[data-bs-theme="light"]') — lets a manual "light" choice beat an OS prefers-color-scheme: dark setting.

Source: src/types.js:150

SemanticRoles

SEMANTIC-ROLE CONTRACT (framework-targets-productization, T0). The canonical set of role ids a token kit MUST expose for the framework TargetAdapter emit formats (sorb/mantine-vars, sorb/mui-vars, sorb/mat-sys-vars, sorb/shadcn-theme, sorb/primevue-preset) to emit correctly. Each format maps its framework's own vars (--mantine-*, --mui-*, --mat-sys-*, shadcn vars, PrimeVue preset roots) ONTO these role ids. These are DTCG dot-path ids (→ CSS var --&lt;kebab&gt; → preview-payload key &lt;kebab&gt;). The Janes Jeans kit (@metatoy/janes-jeans) is the reference implementation. A kit using different names supplies options.roleMap (role-id → its-own-token-id) to a format rather than forking it. SEMVER: adding a role id here is a MINOR bump; renaming or removing one is a MAJOR bump for @sorb/core AND @sorb/seed — every format consumer depends on this set. Scope = the UNION of the target maps' role columns, not a kit's full token tree; anything beyond this list is kit-private.

PropertyTypeDescription
colorstring[]surface/ink/brand/accent/danger/success/border/focus roles.
radiusstring[]control/card/pill.
shadowstring[]raised/overlay.
typographystring[]display/heading/body/caption × fontSize/Weight/lineHeight.

Source: src/types.js:172

ConnectorRegistry

The runtime connector registry — id → impl per axis. The Maps are mutable by design so consumer packages register their defaults into them; the container itself is frozen so the axis set can't drift.

PropertyTypeDescription
sourceMap<string, SourceConnector>
codeSourceMap<string, CodeSourceConnector>
targetMap<string, TargetAdapter>

Source: src/types.js:198

Next

  • @sorb/seed — registers the default source connector; format options.roleMap resolves against this page's role ids.
  • @sorb/leaf — registers the seven target adapters into this registry.
  • @sorb/juice — the bridge that serves ResolvedToken[] at GET /tokens/resolved.

Works with Figma. Not affiliated with, or endorsed by, Figma. Figma is a trademark of Figma, Inc.