storage
Every export of @kitr/storage, @kitr/storage/react, @kitr/storage/server, @kitr/storage/provider, read from the published type definitions. The guide shows them in use.
@kitr/storage
createAsyncStorageDriver
function createAsyncStorageDriver(options: {
name: string;
load(): Promise<Record<string, string>>;
write(key: string, raw: string): Promise<void>;
erase(key: string): Promise<void>;
onError?: (error: unknown) => void;
}): StorageDriver;
Build a driver over an async native store. load runs once at boot and fills the cache;
write/erase run in the background after each change, so reads stay synchronous.
createMemoryStorageDriver
function createMemoryStorageDriver(name?: string): StorageDriver;
In-memory driver: tests, the server, and session items on native platforms.
createWebStorageDriver
function createWebStorageDriver(name: StorageArea): StorageDriver | null;
Web Storage as a driver. Null outside a browser, so items fall back to their defaults.
defineCookie
function defineCookie<T = string>(name: string, options: CookieItemOptions<T>): CookieItem<T>;
A typed cookie, readable on both sides and writable from the browser or the server.
const locale = defineCookie('locale', { default: 'en', maxAge: 60 * 60 * 24 * 365 })
locale.get() // client: document.cookie
locale.get(request.headers) // server: any Headers / Cookie header string
locale.set('de') // client
cookies(event).set(locale, 'de') // server (@kitr/storage/server)
defineStorage
function defineStorage<T>(name: string, options: StorageItemOptions<T>): StorageItem<T>;
A typed item in localStorage or sessionStorage.
const sidebar = defineStorage('sidebar', { default: { open: true } })
sidebar.get().open; sidebar.set((s) => ({ ...s, open: false }))
Safe everywhere: on the server (or when storage is blocked) get() returns the default
and set() is a no-op, so the same module renders on both sides.
getStorageDriver
function getStorageDriver(name: StorageArea): StorageDriver | null;
The driver behind an area: the platform driver, Web Storage, or null on the server.
listStorage
function listStorage(name: StorageArea): Array<{
key: string;
raw: string | null;
}>;
Every key in an area, for the devtools panel.
logStorage
function logStorage(app: KitrApp, label: string, data?: unknown): void;
Write a line to the devtools storage channel. Does nothing when devtools are off.
notifyCookiesChanged
function notifyCookiesChanged(): void;
Call after something else wrote document.cookie so useCookie() re-reads.
parseCookies
function parseCookies(header: string | null | undefined): Record<string, string>;
Parse a Cookie header into a map. Values are decoded with decodeURIComponent.
removeStorageKey
function removeStorageKey(name: StorageArea, key: string): void;
Delete one raw key from an area and notify subscribers. Used by the devtools panel.
serializeCookie
function serializeCookie(name: string, value: string | null, options?: CookieOptions): string;
Build a Set-Cookie value. value === null expires the cookie.
setCookieDefaults
function setCookieDefaults(defaults: Omit<CookieOptions, 'name'>): void;
Attributes merged into every cookie this app writes. The provider sets them from cookie in config.
setStorageDriver
function setStorageDriver(driver: StorageDriver, areas?: {
local?: StorageDriver;
session?: StorageDriver;
}): void;
Replace the Web Storage backing with a platform driver. Called by the storage provider when a
platform registered one (app.drivers.register('storage', driver)); session items keep an
in-memory driver unless areas says otherwise.
setStoragePrefix
function setStoragePrefix(prefix: string): void;
Set by the provider from config/storage.ts; items created later pick it up.
defineConfig
const defineConfig: <const C extends StorageConfig>(config: C) => C;
Type-checks config/storage.ts. Returns the object unchanged.
jsonCodec
const jsonCodec: <T>() => Codec<T>;
The default codec for objects: JSON.stringify and JSON.parse.
stringCodec
const stringCodec: Codec<string>;
Stores strings as they are, with no quotes. The default for cookies whose default is a string.
Codec
interface Codec<T> {
/** Value to stored string. */
encode(value: T): string;
/** Stored string to value. Throwing makes the item fall back to its default. */
decode(raw: string): T;
}
Turns a value into the string that is stored and back. Pass one as codec to change the format.
CookieItem
interface CookieItem<T> {
/** The name it was defined with, without the config prefix. */
readonly name: string;
/** Returned when the cookie is missing or invalid. */
readonly default: T;
/** The attributes given to `defineCookie`. */
readonly options: CookieOptions;
/** Read from `document.cookie`, or from the given source on the server. */
get(source?: CookieSource): T;
/** Write `document.cookie` (client). On the server use `cookies(event).set(item, value)`. */
set(value: T, options?: CookieOptions): void;
/** Expire the cookie in the browser. A no-op on the server. */
remove(): void;
/** Fires after `set`, `remove` or `notifyCookiesChanged()` in this tab. */
subscribe(listener: (value: T) => void): () => void;
/** The `Set-Cookie` header value for this item. */
serialize(value: T | null, options?: CookieOptions): string;
/** Parse one raw cookie value into T (or the default). */
decode(raw: string | undefined): T;
}
A typed cookie returned by defineCookie, readable on both sides.
CookieItemOptions
interface CookieItemOptions<T> extends CookieOptions {
/** Returned when the cookie is missing or invalid. */
default: T;
/** Validate the decoded value (Standard Schema). Invalid → default. */
schema?: StandardSchemaV1<unknown, T>;
/** Default: JSON for objects, plain string for string defaults. */
codec?: Codec<T>;
}
Options for defineCookie: the default, validation, format, and the cookie attributes.
CookieOptions
interface CookieOptions {
/** URL path the cookie is sent for. */
path?: string;
/** Domain the cookie is sent to, e.g. `.acme.com` to share it with subdomains. */
domain?: string;
/** Seconds. */
maxAge?: number;
/** Absolute expiry date. */
expires?: Date;
/** Send only over HTTPS. Forced on when `sameSite` is `none`. */
secure?: boolean;
/** Server-set cookies only; the browser cannot write httpOnly cookies. */
httpOnly?: boolean;
/** Cross-site sending rule. */
sameSite?: 'lax' | 'strict' | 'none';
}
Attributes written into Set-Cookie. path: '/' and sameSite: 'lax' apply unless overridden.
StorageConfig
interface StorageConfig {
/** Prefix for every storage key and cookie name, e.g. `myapp:`. Default none. */
prefix?: string;
/** Defaults merged into every cookie. */
cookie?: Omit<CookieOptions, 'name'>;
}
Options for config/storage.ts: a key prefix and cookie defaults.
StorageDriver
interface StorageDriver {
/** Shown in the devtools log, e.g. `web:local` or `capacitor:preferences`. */
name: string;
/** Load every stored key into memory before the first render. */
hydrate?(): Promise<void>;
/** The raw string stored under `key`, or null. Must answer synchronously. */
get(key: string): string | null;
/** Store a raw string. May persist in the background. */
set(key: string, raw: string): void;
/** Delete one key. */
remove(key: string): void;
/** Every stored key, for the devtools panel. */
keys(): string[];
/** Changes made elsewhere (another tab, the native side). */
subscribe?(listener: (key: string | null) => void): () => void;
}
What a platform supplies to back defineStorage items: Capacitor Preferences on mobile,
the Tauri store or an Electron JSON file on desktop, Web Storage in the browser.
Reads are synchronous from a cache hydrate() fills at boot; writes go through in the background.
StorageItem
interface StorageItem<T> {
/** The name it was defined with, without the config prefix. */
readonly key: string;
/** Which area it lives in. */
readonly area: StorageArea;
/** The stored value, or the default when it is missing, invalid, expired or on the server. */
get(): T;
/** Store a value, or compute it from the current one. A no-op on the server. */
set(value: T | ((current: T) => T)): void;
/** Delete the stored value so `get()` returns the default. */
remove(): void;
/** Fires on set/remove here and in other tabs (`storage` event). */
subscribe(listener: (value: T) => void): () => void;
/** The default, for server snapshots. */
readonly default: T;
}
A typed value in local or session storage, returned by defineStorage.
StorageItemOptions
interface StorageItemOptions<T> {
/** Returned when the key is missing, unparsable, invalid or on the server. */
default: T;
/** Where it is stored. Default `local`. */
area?: StorageArea;
/** Validate what comes back from storage (Standard Schema: zod, valibot...). Invalid → default. */
schema?: StandardSchemaV1<unknown, T>;
/** Format of the stored envelope. Default: JSON. */
codec?: Codec<T>;
/** Bump when the shape changes; stored values with another version are migrated or dropped. */
version?: number;
/** Converts a value stored under an older `version`. Without it, old values are dropped. */
migrate?: (raw: unknown, fromVersion: number) => T;
/** Keep this many ms, then treat as missing. Stored beside the value. */
ttl?: number;
}
Options for defineStorage: the default, the area, and how stored values are checked.
CookieSource
type CookieSource = string | null | undefined | Headers | {
cookie?: string | null;
};
Anything that can hold cookies: a Cookie header string, a Headers object or document.
StorageArea
type StorageArea = 'local' | 'session';
local keeps a value until it is cleared; session keeps it for the current tab.
@kitr/storage/react
CookieHeader
function CookieHeader({ value, children }: {
value: string | null | undefined;
children: ReactNode;
}): import("react").FunctionComponentElement<import("react").ProviderProps<string | null | undefined>>;
Gives useCookie() the request's Cookie header during server rendering, so the first
HTML shows the stored value instead of the default. Wrap the tree once, in the root route.
useCookie
function useCookie<T>(item: CookieItem<T>): [
T,
(value: T) => void,
() => void
];
Read and write a cookie from a component. On the server the value comes from
<CookieHeader> when present, otherwise the default.
useStorage
function useStorage<T>(item: StorageItem<T>): [
T,
(value: T | ((current: T) => T)) => void,
() => void
];
Read and write a storage item from a component. Hydration-safe: the server (and the first client render) see the default, then the stored value applies, so markup always matches.
@kitr/storage/server
cookies
function cookies(event: CookieEventLike): ServerCookies;
function cookies(request: Request, responseHeaders: Headers): ServerCookies;
Typed cookies on the server: cookies(event) in a controller or middleware,
cookies(request, responseHeaders) anywhere you only have the Fetch primitives.
CookieEventLike
interface CookieEventLike {
/** The request; only its headers are read. */
req: {
headers: Headers;
};
/** The response; `Set-Cookie` headers are appended here. */
res: {
headers: Headers;
};
}
The parts of an h3 v2 event (or anything request/response shaped) that cookies need.
ServerCookies
interface ServerCookies {
/** The item's value from the request's `Cookie` header, or its default. */
get<T>(item: CookieItem<T>): T;
/** Appends a `Set-Cookie` header; `httpOnly` and the other item options apply. */
set<T>(item: CookieItem<T>, value: T, options?: CookieOptions): void;
/** Appends a `Set-Cookie` header that expires the cookie. */
remove(item: CookieItem<unknown>): void;
/** The raw `Cookie` header, for `<CookieHeader>` during SSR. */
readonly header: string | null;
}
Typed cookie access for one request, returned by cookies().
@kitr/storage/provider
storageProvider
const storageProvider: import("@kitr/core").KitrProvider;
Applies config/storage.ts (key prefix, cookie defaults), switches defineStorage
items to the platform's native driver when one is registered, hydrates it before the first
render, and contributes the Storage panel to the devtools.