Skip to content

API

ogygia

The runtime surface — Region, region(), script, preference, transport, context.

On this page

Auto-generated from the package’s own .d.ts on every build — signatures, JSDoc, and examples straight from the source.

import { … } from 'ogygia';

Exports __tag_context · createContext · hydratedBy · isRegion · preference · preload · region · script · Context · OgygiaBoundary · Region · ogygiaTransport · Preference · TransportCodec · AwaitableRegion · DeferredRegion · DualRegion · Fallback · InlineRegion · PreferenceSpec · RegionOptions · RegionSchedule · RegionValue

__tag_context

function

Build-generated: bind a createContext() export to its stable module#export tag.

function __tag_context(tag: string, handle: unknown): void;

createContext

function

Define a typed cross-island context. No string key — the build tags it by module#export, so the provider and every consumer island agree on identity without a magic string.

// context.ts
export const cart = createContext<Cart>();          // get(): Cart | undefined
export const theme = createContext('light');        // get(): string (has a default)
function createContext<T>(defaultValue: T): ContextHandle<T> & {
  get(): T;
};
function createContext<T>(): ContextHandle<T>;

hydratedBy

function

hydratedBy() — which schedule woke the hydration root this component is mounting under.

Call during component SETUP (like getContext): the runtime marks the region it is hydrating (the same anchor cross-island context uses), and this reads that region's hydrate attribute.

Why you'd care: an interaction island's first event is a REPLAY — real interaction, but not a trusted browser gesture (event.isTrusted === false), so gesture-gated APIs (window.open, clipboard, fullscreen) will be blocked for it. A component that needs those can check hydratedBy() === 'interaction' and adapt (e.g. render the popup as a link the SECOND click uses, or skip an entrance animation that assumes a fresh load).

Returns:

  • 'load' | 'idle' | 'visible' | 'interaction' or a media-query string — the region's schedule
  • null on the server (SSR pass), and on csr=true pages where Kit (not ogygia) hydrates.

A nested island hydrates with its parent, so it reports the PARENT region's schedule — correct: that is the wake that ran its code.

function hydratedBy(): string | null;

isRegion

function

True for any value produced by region (or decoded from the wire).

function isRegion(value: unknown): value is RegionValue;

preference

function

const preference: typeof preference_impl & {
  switch: typeof preference_switch;
}

preload

function

function preload(region: unknown): void;

region

function

Make a held region with type-checked props.

  • A plain component import → an inline region (renders in this pass; can't cross the wire).
  • A component imported with { region: 'raw' } → a dual region: inline where it's made, a signed ticket where it travels. Minting the marked form is server-only (the signer lives on the SSR leg) — call it in a load / remote / render context.

A dual region is awaitable. await region(Card, props) renders the component to HTML on the server and bakes it into the ticket, so the client swaps it in with no extra request. In an async generator (query.live) or an async remote, yield region(…) / return region(…) is awaited by the language, so the HTML travels automatically — LiveView over the channel you already have. A held region you don't await renders inline where it lands (first paint, same SSR pass).

function region<C extends Component<never>>(component: C, props: ComponentProps<C>, opts?: RegionSchedule<ComponentProps<C>>,
content_id?: string): AwaitableRegion;

script

function

Serialize a self-contained function into a blocking inline <script> string.

csr=false apps routinely need a tiny script that runs BEFORE hydration and first paint — set the theme so there's no dark-mode flash, kick off a deferred font, read an early flag. A normal client import can't do it (islands hydrate later), so you hand-roll a <script> string — and a literal </script> inside a Svelte component prematurely closes the component's own script, which is why people resort to String.fromCharCode(60) tricks. This removes all of that: pass a function, get back a <script>…</script> string, and {@html} it wherever you want the tag to land — usually <svelte:head>, but it's just a string, so it's up to you.

The function is inlined via Function.prototype.toString, so it must be self-contained — only browser globals, no imports and no closed-over variables (they won't exist at runtime). For values you would otherwise close over (a hashed asset URL, a config flag), pass them as trailing args; they are JSON-serialized and handed to the function as parameters.

function script<A extends unknown[]>(fn: (...args: A) => void, ...args: A): string;
  • fn — A self-contained function run synchronously, before paint.
  • args — Serializable values (string/number/boolean/null/plain JSON) passed to fn in order.

Returns A <script>…</script> string to {@html} wherever you want the tag.

No-flash theme (no args)

<svelte:head>
{@html script(() => {
try {
var t = localStorage.getItem('theme');
if (t === 'light' || t === 'dark') document.documentElement.setAttribute('data-theme', t);
} catch (e) {}
})}
</svelte:head>

Deferred font loader (a URL passed as an arg)

<svelte:head>
{@html script((href) => {
addEventListener('load', () => {
var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = href;
document.head.appendChild(l);
}, { once: true });
}, fontUrl)}
</svelte:head>

Context

component

import Context from 'ogygia';

OgygiaBoundary

component

import OgygiaBoundary from 'ogygia';

Region

component

import Region from 'ogygia';

ogygiaTransport

const

const ogygiaTransport: {
  Region: {
    encode(value: unknown): false | EncodedRegion;
    decode(raw: EncodedRegion): {
      html?: string;
      hydrateMargin?: string;
      hydrate?: string;
      [REGION_BRAND]: boolean;
      kind: "deferred";
      id: string;
      props: Record<string, unknown>;
      url: string;
      module: string;
    };
  };
}

Preference

interface

A live preference handle — SSR head(), client get()/set(), and the attr CSS authors target.

interface Preference {/*…*/}

Preference.name

readonly name: string;

Preference.values

readonly values: readonly string[];

Preference.default

readonly default: string;

Preference.attr

The attribute set on <html>: data-pref-<name>. CSS targets :root[<attr>="<value>"].

readonly attr: string;

Preference.head

No-flash inline <script> string — reads localStorage and applies the attr before paint. {@html} it once in <svelte:head>. Idempotent, so emitting it more than once is harmless.

head(): string;

Preference.set

CLIENT: persist + apply a new value (wire a control's handler to this). No-op on the server.

set(value: string): void;

Preference.get

CLIENT: the current value (from the applied attr), or the default. Returns the default on the server.

get(): string;

TransportCodec

interface

The codec import.meta.og.wire({ … }) carries (or a static method returning it).

interface TransportCodec<T = unknown, D = unknown> {/*…*/}

TransportCodec.encode

Sending side: turn the live instance into devalue-safe data.

encode: (value: T) => D;

TransportCodec.decode

Receiving side: rebuild a live instance from that data.

decode: (data: D) => T;

TransportCodec.id

CONTINUITY — a stable session name. Naming the codec promotes the instance from page lifetime to SESSION lifetime: it becomes a singleton in this browser tab, and a navigation reunites the next page's decode with the SAME live instance instead of rebuilding it. Tab- scoped only — the server stays per-request (never remembers), a reload starts fresh.

id?: string;

TransportCodec.merge

Reconcile a navigation: the tab already holds the live named instance and the new page's server snapshot just arrived (decoded as fresh). Apply whatever should carry over INTO live — its identity is preserved; fresh is discarded afterwards. Default: do nothing (live wins — continuity is the point; a cart mid-edit beats a server re-read). Override to pull server truth in (prices, stock, auth state).

merge?: (live: T, fresh: T) => void;

AwaitableRegion

type

What region returns: a RegionValue you can render right now with <Region of={…} />, AND a PromiseLike<Region> you can await to bake its server-rendered HTML into the ticket. In an async generator (query.live) or async remote, yield / return awaits it for you.

type AwaitableRegion = RegionValue & PromiseLike<RegionValue>;

DeferredRegion

type

A held region that arrived over the wire: a signed capability, no component.

type DeferredRegion = {
  readonly [REGION_BRAND]: true;
  readonly kind: 'deferred';
  readonly id: string;
  readonly props: Record<string, unknown>;
  readonly url: string;
  readonly module: string;
  readonly hydrate?: string;
  readonly hydrateMargin?: string;
  readonly html?: string;
};

DualRegion

type

A marked component: renders inline here, or becomes a signed ticket when it crosses the wire.

type DualRegion = {
  readonly [REGION_BRAND]: true;
  readonly kind: 'dual';
  readonly component: AnyComponent;
  readonly props: Record<string, unknown>;
  readonly id: string;
  readonly module: string;
  readonly hydrate?: string;
  readonly hydrateMargin?: string;
  readonly sign: (id: string, props: Record<string, unknown>) => string;
  readonly renderHtml?: (props: Record<string, unknown>) => string | Promise<string>;
  readonly html?: string;
};

Fallback

type

type Fallback<P = unknown> = P & {
  ogygiaFallback?: import('svelte').Snippet;
};

InlineRegion

type

A plain component. Renders in the current server pass; awaiting it bakes its SSR HTML so it can cross the wire as an HTML-only ticket (no chunk, no signer — nothing to fetch).

type InlineRegion = {
  readonly [REGION_BRAND]: true;
  readonly kind: 'inline';
  readonly component: AnyComponent;
  readonly props: Record<string, unknown>;
  readonly html?: string;
  readonly content_id?: string;
};

PreferenceSpec

type

A preference declaration: its name, allowed values, and default (which must be one of the values).

type PreferenceSpec = {
  name: string;
  values: readonly string[];
  default: string;
};

RegionOptions

type

Schedule options for a held region. wake = when its JS runs; margin = IntersectionObserver rootMargin for wake: 'visible'. Merged OVER the binding's baked schedule (from a wake: mark) — anything set here WINS; a region: 'raw' binding bakes nothing, so this is the whole schedule.

type RegionOptions = {
  wake?: string;
  margin?: string;
};

RegionSchedule

type

The region() schedule argument: a function handed the component's own props (its "generated data") that returns the schedule. Always a function, never a bare object — the object case is the baked wake: mark on the import. The function is for a registry of region: 'raw' components that decides each one's timing from its data — e.g. region(block, data, (d) => ({ wake: d.interactive ? 'load' : undefined })).

type RegionSchedule<P = Record<string, unknown>> = (data: P) => RegionOptions;

RegionValue

type

type RegionValue = InlineRegion | DualRegion | DeferredRegion;