/** * vapor-chamber — IIFE variant: FULL * * Exposes the full vapor-chamber API as `window.VaporChamber`. For sites that * want every feature in a single ` * * */ import { createCommandBus, createAsyncCommandBus, type CommandBusOptions, } from './command-bus'; import { logger, validator, history, debounce, throttle, authGuard, optimistic, retry, persist, sync, } from './plugins'; import { createHttpBridge, createWsBridge, createSseBridge, type HttpBridgeOptions, } from './transports'; import { defineVaporCustomElement, defineVaporComponent, defineVaporAsyncComponent, defineVaporCommand, useVaporAsyncCommand, createVaporChamberApp, getVaporInteropPlugin, } from './chamber-vapor'; import { useSharedCommandState, useCommand } from './chamber'; import type { AsyncPlugin, Plugin } from './command-bus'; // --------------------------------------------------------------------------- // createApp — convenience entry point for CDN usage // --------------------------------------------------------------------------- export type CreateAppOptions = { /** * An async transport plugin (e.g. createHttpBridge) to install on the bus. * Commands without a local handler are forwarded through this transport. */ transport?: AsyncPlugin; /** * Plugins to install on the bus (sync or async). */ plugins?: Plugin[]; /** * Dead-letter mode. Default: 'error' */ onMissing?: CommandBusOptions['onMissing']; }; /** * createApp — creates a configured command bus, installs transport + plugins. * * @example * const { bus, dispatch } = VaporChamber.createApp({ * transport: VaporChamber.http({ endpoint: '/api/vc' }) * }) * dispatch('cartAdd', { id: 1 }, { quantity: 2 }) */ function createApp(options: CreateAppOptions = {}): { bus: ReturnType; dispatch: ReturnType['dispatch']; } { const bus = createAsyncCommandBus({ onMissing: options.onMissing ?? 'error' }); if (options.plugins) { for (const plugin of options.plugins) bus.use(plugin as AsyncPlugin); } if (options.transport) { bus.use(options.transport); } return { bus, dispatch: bus.dispatch.bind(bus) }; } // --------------------------------------------------------------------------- // mount — mount a command-bus-driven island to a DOM element // --------------------------------------------------------------------------- export type MountOptions = CreateAppOptions & { /** * Initial state object. Not reactive on its own — use with your own * signal library or Vue's ref() for reactivity. */ state?: Record; }; /** * mount — attach a command bus island to a specific DOM element. * * @example * VaporChamber.mount('#analytics-island', { * transport: VaporChamber.http({ endpoint: '/api/vc' }), * state: { period: 'week', metrics: [] } * }) */ function mount(selector: string, options: MountOptions = {}): { bus: ReturnType; dispatch: ReturnType['dispatch']; state: Record; el: Element | null; } { const el = typeof document !== 'undefined' ? document.querySelector(selector) : null; const { state = {}, ...appOptions } = options; const app = createApp(appOptions); return { ...app, state, el }; } /** * connect — one-line setup mirroring the CORE variant's API. Equivalent to * `createApp({ transport: createHttpBridge({ csrf: true, ...opts }) })`. * Available in every variant so the same call site works regardless of which * IIFE bundle is loaded. */ function connect(options: HttpBridgeOptions & { plugins?: Plugin[]; onMissing?: CommandBusOptions['onMissing'] }) { const { plugins, onMissing, ...httpOptions } = options; return createApp({ transport: createHttpBridge({ csrf: true, ...httpOptions }), plugins, onMissing, }); } /** * defineWidget — one-line custom-element registration mirroring the ELEMENTS * variant's API. Returns `false` if Vue 3.6+ Vapor is not detected. */ function defineWidget(tagName: string, options: any, extraOptions?: any): boolean { const El = extraOptions !== undefined ? defineVaporCustomElement(options, extraOptions) : defineVaporCustomElement(options); if (!El) return false; if (typeof customElements === 'undefined') return false; if (customElements.get(tagName)) return true; customElements.define(tagName, El); return true; } /** * emitDOMEvent — bridge Vue's component emit() to a real DOM CustomEvent so * host pages can `addEventListener` on the widget tag. See ELEMENTS variant * for the full doc + attribution. */ function emitDOMEvent( el: Element, eventName: string, detail?: any, options: { bubbles?: boolean; composed?: boolean; cancelable?: boolean } = {}, ): boolean { if (typeof CustomEvent !== 'function' || !el) return true; const event = new CustomEvent(eventName, { detail, bubbles: options.bubbles ?? true, composed: options.composed ?? true, cancelable: options.cancelable ?? false, }); return el.dispatchEvent(event); } // --------------------------------------------------------------------------- // Global VaporChamber namespace // --------------------------------------------------------------------------- const VaporChamber = { // --- Core factories --- createCommandBus, createAsyncCommandBus, // --- Convenience --- createApp, connect, mount, defineWidget, emitDOMEvent, // --- Transport shortcuts --- /** HTTP fetch transport. Alias for createHttpBridge(). */ http: createHttpBridge, /** WebSocket transport. Alias for createWsBridge(). */ ws: createWsBridge, /** Server-sent events bridge. Alias for createSseBridge(). */ sse: createSseBridge, // --- Plugins --- logger, validator, history, debounce, throttle, authGuard, optimistic, retry, persist, sync, // --- Vapor (Vue 3.6+) --- defineVaporCustomElement, defineVaporComponent, defineVaporAsyncComponent, defineVaporCommand, useCommand, useVaporAsyncCommand, useSharedCommandState, createVaporChamberApp, getVaporInteropPlugin, } as const; // Assign to globalThis so it's accessible as window.VaporChamber in browsers if (typeof globalThis !== 'undefined') { (globalThis as any).VaporChamber = VaporChamber; } // Default export only: the IIFE build assigns the DEFAULT export to the // `VaporChamber` global, so the API object lands directly on window // (`VaporChamber.connect(...)`). A second named export would force the // bundler to emit a module-namespace wrapper — `{ VaporChamber, default }` // — and every documented call site would be undefined in a