@molecule/app-bond
Infrastructure · bond · App (browser) · v1.0.3 · Apache-2.0
Provider wiring mechanism for app-side packages
npm install @molecule/app-bondHow it works
@molecule/app-bond is a infrastructure package for the app (browser) side (bond).
import { bond, get, require as bondRequire, isBonded } from '@molecule/app-bond'
import { provider as routingProvider } from '@molecule/app-routing-react-router'
import type { StateProvider } from '@molecule/app-state'
import { provider as stateProvider } from '@molecule/app-state-zustand'
import type { ThemeProvider } from '@molecule/app-theme'
import { provider as themeProvider } from '@molecule/app-theme-css-variables'
// Singleton providers (one per category)
bond('state', stateProvider)
bond('theme', themeProvider)
// Named providers (multiple per category)
bond('routing', 'react', routingProvider)
// Retrieve providers
const state = get<StateProvider>('state') // undefined if not bonded
const theme = bondRequire<ThemeProvider>('theme') // throws if not bonded
const router = get('routing', 'react')
// Check before using
if (isBonded('routing', 'react')) {
// ...
}Reference
Runtime provider wiring system for molecule.dev app-side packages.
Enables swappable providers for state management, theming, routing, styling,
and any custom category — all through dynamic string-based keys. Most app
cores' own setup helpers (setFont, setRouter, setClassMap, each
setProvider) delegate INTO this registry, so bond('theme', p) and
@molecule/app-theme's setProvider(p) write the same slot — use either.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { bond, get, require as bondRequire, isBonded } from '@molecule/app-bond'
import { provider as routingProvider } from '@molecule/app-routing-react-router'
import type { StateProvider } from '@molecule/app-state'
import { provider as stateProvider } from '@molecule/app-state-zustand'
import type { ThemeProvider } from '@molecule/app-theme'
import { provider as themeProvider } from '@molecule/app-theme-css-variables'
// Singleton providers (one per category)
bond('state', stateProvider)
bond('theme', themeProvider)
// Named providers (multiple per category)
bond('routing', 'react', routingProvider)
// Retrieve providers
const state = get<StateProvider>('state') // undefined if not bonded
const theme = bondRequire<ThemeProvider>('theme') // throws if not bonded
const router = get('routing', 'react')
// Check before using
if (isBonded('routing', 'react')) {
// ...
}
Type
infrastructure
Installation
npm install @molecule/app-bond
API
Interfaces
Provider
Minimal base interface that every bondable provider can optionally satisfy.
Provider implementations may include a name for logging and debugging
but are not required to extend this interface.
interface Provider {
/**
* Optional human-readable identifier for this provider, used in log
* output and error messages.
*/
readonly name?: string
}
ProviderRegistry
Internal data structure that holds all bonded providers at runtime. The registry distinguishes between singleton providers (one per category) and named providers (multiple per category, keyed by a string name).
interface ProviderRegistry {
/**
* Map from category string (e.g. `'state'`, `'theme'`) to the single
* active provider instance for that category.
*/
singletons: Map<string, unknown>
/**
* Two-level map: outer key is the category string (e.g. `'routing'`),
* inner key is the provider name (e.g. `'react'`), value is the provider instance.
*/
named: Map<string, Map<string, unknown>>
}
BondConfig
Options that control bond registration behavior.
interface BondConfig {
/**
* When `true`, bonding a provider to a category that already has a bonded
* provider throws an error instead of silently replacing it.
* @default false
*/
strict?: boolean
/**
* When `true`, every bond / unbond / clear / reset operation emits a
* diagnostic line via `console.debug` (prefixed `[app-bond]`). Useful for
* tracing wiring order at startup; leave `false` in production.
* @default false
*/
verbose?: boolean
}
Functions
bond(type, provider)
Registers a provider at runtime. With two arguments, bonds a singleton provider for the category. With three arguments, bonds a named provider under the category.
function bond(type: string, provider: unknown): void
type— The provider category (e.g.'state','theme','routing').provider— The provider instance to bond as a singleton.
get(type)
Retrieves a bonded singleton provider by category, or undefined if not bonded.
function get(type: string): T | undefined
type— The provider category to look up.
Returns: The bonded provider instance, or undefined if not bonded.
getAll(type)
Retrieves all named providers bonded under a category. Returns an empty Map if no named providers exist for the category.
function getAll(type: string): Map<string, T>
type— The provider category to look up.
Returns: A Map from provider name to provider instance.
require(type)
Retrieves a bonded singleton provider, throwing if not bonded. Use this when the provider is required for the application to function.
function require(type: string): T
type— The provider category to look up.
Returns: The bonded provider instance.
unbond(type)
Removes a bonded singleton provider from a category.
function unbond(type: string): boolean
type— The provider category to unbond.
Returns: true if a provider was removed, false if none was bonded.
unbondAll(type)
Removes all providers (both singleton and named) for a category.
function unbondAll(type: string): void
type— The provider category to clear entirely.
isBonded(type)
Checks whether a singleton provider is bonded for a category.
function isBonded(type: string): boolean
type— The provider category to check.
Returns: true if a singleton provider is bonded for the category.
configure(newConfig)
Merges new configuration options into the current bond configuration.
function configure(newConfig: Partial<BondConfig>): void
newConfig— Partial configuration to merge. Unspecified fields retain their current values.
bondSingleton(type, provider)
Registers a singleton provider for the given category. If provider is null/undefined,
the existing singleton for that category is removed instead. In strict mode, throws
if a provider is already bonded to the category.
function bondSingleton(type: string, provider: T): void
type— The provider category (e.g.'state','theme','routing').provider— The provider instance to bond, or null/undefined to remove.
getSingleton(type)
Retrieves the singleton provider for a category, or undefined if none is bonded.
function getSingleton(type: string): T | undefined
type— The provider category to look up.
Returns: The bonded provider instance cast to T, or undefined if not bonded.
requireSingleton(type)
Retrieves the singleton provider for a category, throwing if none is bonded. Use this when the provider is required for the application to function.
The error distinguishes the two ways this fails, because they need different fixes: if nothing has been bonded yet the accessor ran BEFORE the app's bond setup (a module-level call, which executes at import time — move it into a function/hook/effect), while if other categories are bonded the setup ran and this one was simply never wired. Both messages name the calling module.
function requireSingleton(type: string): T
type— The provider category to look up.
Returns: The bonded provider instance cast to T.
bondNamed(type, name, provider)
Registers a named provider under a category. Named providers allow multiple
implementations per category (e.g. bond('routing', 'react', reactProvider)).
In strict mode, throws if that name is already bonded in the category.
function bondNamed(type: string, name: string, provider: T): void
type— The provider category (e.g.'routing','oauth').name— The unique name within the category (e.g.'react','github').provider— The provider instance to bond.
getNamed(type, name)
Retrieves a named provider from a category, or undefined if not bonded.
function getNamed(type: string, name: string): T | undefined
type— The provider category to look up.name— The provider name within the category.
Returns: The bonded provider instance cast to T, or undefined if not found.
getAllNamed(type)
Retrieves all named providers bonded under a category as a Map keyed by provider name. Returns an empty Map if no providers are bonded for the category.
function getAllNamed(type: string): Map<string, T>
type— The provider category to look up.
Returns: A Map from provider name to provider instance for the given category.
requireNamed(type, name)
Retrieves a named provider from a category, throwing if not bonded. Use this when the provider is required for the application to function.
Like requireSingleton, the error says whether the call ran before
the app's bond setup or whether the setup ran without wiring this provider,
and names the calling module.
function requireNamed(type: string, name: string): T
type— The provider category to look up.name— The provider name within the category.
Returns: The bonded provider instance cast to T.
unbondSingleton(type)
Removes a singleton provider from a category.
function unbondSingleton(type: string): boolean
type— The provider category to unbond.
Returns: true if a provider was removed, false if none was bonded.
unbondNamed(type, name)
Removes a named provider from a category.
function unbondNamed(type: string, name: string): boolean
type— The provider category containing the named provider.name— The provider name to remove.
Returns: true if the provider was removed, false if it was not found.
clearProviders(type)
Removes all providers (both singleton and named) for a given category.
function clearProviders(type: string): void
type— The provider category to clear.
reset()
Removes all bonded providers across all categories, restoring the registry to its initial empty state. Primarily used in test teardown.
function reset(): void
Constants
registry
Global provider registry instance shared across all bond operations. Contains both singleton providers (one per category) and named providers (multiple per category, keyed by name).
const registry: ProviderRegistry
config
Current bond configuration controlling strict mode and verbosity.
const config: BondConfig
Injection Notes
- Wire before ANY module evaluates a bond-backed accessor.
get()returnsundefinedandrequire()THROWS until a provider is bonded — and app modules are imported (module top-level runs) BEFORE yoursetupProviders()/bonds/index.tsexecutes. A module-scopeconst cm = getClassMap()orconst router = require('routing')in a component file therefore runs pre-wiring and breaks the app at load. Call accessors inside components/functions, never at module top-level. The thrown error says WHICH case it is — "ran before the app's bonds were set up" (nothing bonded yet: this call is at module scope, so move it into a function/hook/effect or import the module aftersetupProviders()), or "the app's bond setup has already run" (other categories are bonded and this one was never wired: addbond(...)to the file that definessetupProviders()) — and names the calling module from the stack. - All cores now read this registry. Every
@molecule/app-*core routes itssetProvider()/getProvider()through this bond registry (the ai-*, audio, color-picker, date-range-picker, gallery, image-crop, keyboard-shortcuts, markdown, stepper, timeline, tour, tree-view, battery, bluetooth, brightness, nfc, and screen-orientation cores were migrated off their old module-local singletons), sobond('<category>', p)and the core's ownsetProvider()write the same slot. Use either. - Re-bonding a category silently replaces the provider (last bond wins).
Call
configure({ strict: true })to make double-bonding throw instead.bond(type, null)/bond(type, undefined)REMOVES the singleton for that category.configure({ verbose: true })logs each bond / unbond / clear / reset toconsole.debug(prefixed[app-bond]) for wiring-order tracing. requirecollides with CommonJS — import it renamed:import { require as bondRequire } from '@molecule/app-bond'.