### Using createMemoryStorage with createStorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Example of using createMemoryStorage with createStorage to create a test storage with a prefix. Demonstrates setting and getting an item. ```ts import { createMemoryStorage, createStorage } from 'ultrastorage'; const testStorage = createStorage({ prefix: 'test', storage: createMemoryStorage(), }); testStorage.setItem('theme', 'dark'); testStorage.getItem('theme'); // 'dark' ``` -------------------------------- ### Install ultrastorage with npm Source: https://github.com/yangshun/ultrastorage/blob/main/docs/getting-started.mdx Install the ultrastorage package, which includes the storage API and optional React adapter. ```sh npm install ultrastorage ``` -------------------------------- ### Using appStorage with setItem and getItem Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Shows basic usage of the appStorage instance created earlier. Methods follow the familiar Storage API and accept rich JavaScript values. The example sets and gets a theme value. ```typescript import { appStorage } from './lib/app-storage'; appStorage.setItem('theme', 'dark'); appStorage.getItem('theme'); // 'dark' ``` -------------------------------- ### Initialize Value with getOrInit Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Example of initializing a preferences object when the key is missing or null. ```ts const preferences = appStorage.getOrInit('preferences', () => ({ theme: 'system', locale: 'en', })); ``` -------------------------------- ### Subscribe to Key Changes Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Example of subscribing to changes on the 'theme' key and logging the new value. ```ts const unsubscribe = appStorage.subscribe('theme', (change) => { const theme = appStorage.getItem<'light' | 'dark'>('theme'); console.log(change.type, theme); }); appStorage.setItem('theme', 'dark'); // Logs: set dark unsubscribe(); ``` -------------------------------- ### useStorage(storage, key, options?) Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/react.mdx Documentation for the useStorage React hook, including parameters, read options, return values, and a usage example. ```APIDOC ## `useStorage(storage, key, options?)` ### Description Subscribes to a key and returns its current value with callbacks to write or remove it. Calling this hook directly is equivalent to calling a bound hook. Use `useStorage()` when choosing the storage instance is part of the component's job, such as when the instance comes from props or context, can change, or for one-off calls. ### Parameters - **storage** (`UltraStorage`) - Required - Factory-created instance from `ultrastorage` or `ultrastorage/core`. - **key** (`StorageKey`) - Required - String or ordered array of string segments relative to the namespace. - **options** (`UseStorageOptions`) - Optional - Optional display fallback and synchronous read schema. ### Read Options - **defaultValue** - Display-only fallback when the read returns `null`; never automatically written. An omitted or `undefined` default uses `null`. - **reactiveExpiration** (boolean, default `false`) - Update at expiration without deleting data; timers may run late. - **schema** - Synchronous Standard Schema validation and transformation, matching `getItem()`. Infer the value type from its output. ### Returns Returns a tuple `[value, setValue, removeValue]` where: - **value** - The current value, inferred from schema and default. - **setValue** - Callback to write a new value, accepting write options such as `ttl` or `expiresAt`. - **removeValue** - Callback to remove the key. ### Example ```tsx daily-counter.tsx import type { UltraStorage } from 'ultrastorage'; import { useStorage } from 'ultrastorage/react'; import { z } from 'zod'; const CountSchema = z.number().int().nonnegative(); export function DailyCounter({ storage }: { storage: UltraStorage }) { const [count, setCount, removeCount] = useStorage(storage, 'count', { schema: CountSchema, defaultValue: 0, }); function increment() { const midnight = new Date(); midnight.setHours(24, 0, 0, 0); setCount((previous) => previous + 1, { expiresAt: midnight }); } return ( <> ); } ``` ``` -------------------------------- ### Setting and getting with array keys Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Demonstrates using array keys to preserve structural segments. The example stores a user object with an array key and retrieves it. ```typescript const userId = '42'; appStorage.setItem('theme', 'dark'); appStorage.setItem(['users', userId], { name: 'Alice', role: 'admin', }); appStorage.getItem(['users', userId]); // { name: 'Alice', role: 'admin' } ``` -------------------------------- ### setItem() with ttl example Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md TypeScript example storing a rich object with a one-day TTL using the ttl option. Demonstrates how to serialize and store structured data with expiration. ```typescript appStorage.setItem( 'draft', { title: 'Introducing ultrastorage', updatedAt: new Date(), }, { ttl: 86_400_000 }, ); ``` -------------------------------- ### Create storage instance with prefix Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/subscriptions.md Creates a storage instance with a prefix 'app' using createStorage from ultrastorage. This instance is used in subsequent examples to subscribe and set items. ```ts import { createStorage } from 'ultrastorage'; export const appStorage = createStorage({ prefix: 'app' }); ``` -------------------------------- ### Notify subscriber from another module Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/subscriptions.md Creates a separate storage instance with the same prefix and sets the 'theme' key, which notifies the subscriber from the previous example synchronously. ```ts import { createStorage } from 'ultrastorage'; const appStorage = createStorage({ prefix: 'app' }); appStorage.setItem('theme', 'dark'); // Notifies this page synchronously. ``` -------------------------------- ### Use custom storage with createMemoryStorage Source: https://github.com/yangshun/ultrastorage/blob/main/README.md Pass localStorage, sessionStorage, or any object implementing Storage. Use createMemoryStorage() for tests and server-side rendering. The example uses a memory storage when window is undefined. ```ts import { createStorage, createMemoryStorage } from 'ultrastorage'; const appStorage = createStorage({ prefix: 'acme', storage: typeof window === 'undefined' ? createMemoryStorage() : undefined, }); ``` -------------------------------- ### getItemResult() usage example Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md TypeScript example showing how to handle different read statuses from getItemResult, including success, missing, and validation-error. Demonstrates that a stored null is a successful read. ```typescript const result = appStorage.getItemResult('theme'); if (result.status === 'success') { console.log(result.value); // A stored null is a successful read. } else if (result.status === 'missing') { appStorage.setItem('theme', 'light'); } else if (result.status === 'validation-error') { console.error(result.issues); } ``` -------------------------------- ### Create storage instance with prefix Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/validation.mdx Creates a storage instance with a prefix 'acme'. This instance is used in subsequent examples to read and write values. ```ts import { createStorage } from 'ultrastorage'; export const appStorage = createStorage({ prefix: 'acme' }); ``` -------------------------------- ### Custom separator example: prefix 'acme' with separator '/' Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/namespaces.mdx Creates a storage instance with a custom separator '/' to match an existing stored-key convention. The stored key becomes 'acme/theme'. ```ts import { createStorage } from 'ultrastorage'; export const appStorage = createStorage({ prefix: 'acme', separator: '/' }); ``` ```ts import { appStorage } from './lib/app-storage'; appStorage.setItem('theme', 'dark'); // stored key: acme/theme ``` -------------------------------- ### Reserved array-key encoding example Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Illustrates that a string exactly matching a canonical array encoding addresses the same entry. Be aware of the reserved prefix '\u0000us:a:'. ```typescript appStorage.setItem(['users', '42'], 'Alice'); appStorage.getItem('\u0000us:a:["users","42"]'); // 'Alice' ``` -------------------------------- ### Subscribe to a key with appStorage.subscribe Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/subscriptions.md Shows how to subscribe to a key using an array key. The listener is not called immediately and returns an unsubscribe function. The example also demonstrates setting the same key to trigger the subscription. ```ts import { appStorage } from './lib/app-storage'; const key = ['users', userId] as const; const unsubscribe = appStorage.subscribe(key, () => { const user = appStorage.getItem(key); }); appStorage.setItem(['users', userId], user); // Notifies the subscription. ``` -------------------------------- ### Use namespaced storage: set, get, and clear scoped to prefix Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/namespaces.mdx Demonstrates that setItem stores keys with the prefix, getItem retrieves them, and clear() only removes keys within the namespace. Also shows that localStorage.getItem('theme') returns null because the key is prefixed. ```ts import { appStorage } from './lib/app-storage'; appStorage.setItem('theme', 'dark'); // stored as "acme:theme" appStorage.getItem('theme'); // 'dark' localStorage.getItem('theme'); // null // clear() only removes keys within the namespace appStorage.clear(); ``` -------------------------------- ### Control expiration with updateItem Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/values.mdx The first example sets an initial TTL and then updates without expiration options, preserving the original expiration deadline. The second passes a new TTL to updateItem, restarting the lifetime so the value expires 60 seconds after the update. Omitting expiration options preserves the current unexpired deadline; passing a TTL starts a new lifetime from the update. ```TypeScript appStorage.setItem('count', 1, { ttl: 60_000 }); appStorage.updateItem('count', (current) => (current ?? 0) + 1); // 'count' keeps its original expiration deadline. appStorage.updateItem('count', (current) => (current ?? 0) + 1, { ttl: 60_000 }); // 'count' now expires 60 seconds after this update. ``` -------------------------------- ### getOrInit() Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Returns the existing value for a key, or calls a factory function to create, store, and return a new value. Useful for initializing values and migrating from localStorage. ```APIDOC ## getOrInit() ### Description Returns the existing value for `key`, or calls `factory()` to create, store, and return a new value. This is useful for initializing values when an ordinary read returns `null`. ### Method Not applicable (SDK method) ### Endpoint Not applicable (SDK method) ### Parameters #### Parameters - **key** (`StorageKey`) - Required - The key to retrieve or initialize. - **factory** (`() => T`) - Required - Synchronous function that returns the value to store if the key is missing, expired, unreadable, or stored as `null`. - **options** (`StorageOptions`) - Optional - Configuration options for expiration. #### Options - **ttl** (`number`) - Optional - Finite time-to-live in milliseconds. Cannot be used with `expiresAt`. - **expiresAt** (`Date | number | null`) - Optional - Absolute deadline; `null` removes expiration. Cannot be used with `ttl`. ### Request Example ```ts const preferences = appStorage.getOrInit('preferences', () => ({ theme: 'system', locale: 'en', })); ``` ### Response #### Success Response Returns the existing value for `key`, or the value returned by `factory()` after storing it. #### Response Example ```ts const theme = appStorage.getOrInit('theme', () => localStorage.getItem('theme')); ``` ``` -------------------------------- ### Create and use a prefixed storage instance Source: https://github.com/yangshun/ultrastorage/blob/main/README.md Create a singleton storage instance with a prefix and use it to store and retrieve objects without JSON.stringify/parse. The first block defines the instance in lib/app-storage.ts; the second block imports and uses it in app.ts. ```ts // lib/app-storage.ts import { createStorage } from 'ultrastorage'; // Create an app-wide singleton instance. export const appStorage = createStorage({ prefix: 'acme' }); ``` ```ts // app.ts import { appStorage } from './lib/app-storage'; appStorage.setItem('user', { name: 'Alice', age: 30 }); appStorage.getItem('user'); // { name: 'Alice', age: 30 } ``` -------------------------------- ### has() usage example in app.ts Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Shows checking for a key before setting a default value. ```typescript if (!appStorage.has('preferences')) { appStorage.setItem('preferences', { theme: 'system' }); } ``` -------------------------------- ### Subscribe to theme key and apply theme Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/subscriptions.md Subscribes to the 'theme' key, logging change details and applying the theme. The listener is not invoked immediately upon subscription. ```ts import { appStorage } from './lib/app-storage'; function applyTheme() { document.documentElement.dataset.theme = appStorage.getItem('theme') ?? 'system'; } const unsubscribe = appStorage.subscribe('theme', (change) => { console.log(change.key); // 'theme' console.log(change.type); // 'set' | 'remove' | 'expire' console.log(change.source); // 'local' | 'external' applyTheme(); }); applyTheme(); // Subscribing does not invoke the listener immediately. ``` -------------------------------- ### createStorage() Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Creates a new storage instance with optional configuration for prefix, separator, storage backend, serializer, fallback parser, and quota handling. ```APIDOC ## createStorage() ### Description Creates a new storage instance with optional configuration. ### Method createStorage ### Signature createStorage(options?: CreateStorageOptions): UltraStorage; ### Parameters #### Options (all optional) - **prefix** (string) - Optional - Key prefix for namespacing - **separator** (string) - Optional - Default `":"` - Advanced override for the separator between prefix and key - **storage** (Storage) - Optional - Default `localStorage` - Where values are saved - **serializer** (Serializer) - Optional - Default `devalue` - Custom serializer with `stringify` and `parse` methods - **fallbackParser** (Serializer['parse']) - Optional - Disabled - Synchronous parser tried only after the configured parser throws - **onQuotaExceeded** ('clear-expired') - Optional - Disabled - Clear expired entries in this namespace and retry a failed quota write once ### Returns Returns an `UltraStorage` instance. ### Usage Notes - `getItem()` returns deserialized values rather than always returning strings. - Named property access such as `storage.theme` is unsupported; use `getItem('theme')` and `setItem('theme', value)`. - Existing raw storage values require explicit migration, and `clear()` only removes recognized entries within the configured namespace. ### Example ```ts import { createStorage } from 'ultrastorage'; export const appStorage = createStorage({ prefix: 'acme' }); ``` ``` -------------------------------- ### removeItem() usage example in app.ts Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Shows removing a key and then reading it to confirm it is null. ```typescript appStorage.removeItem('draft'); appStorage.getItem('draft'); // null ``` -------------------------------- ### Migrate localStorage with getOrInit Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Using getOrInit to migrate an existing value from standard localStorage. ```ts const theme = appStorage.getOrInit('theme', () => localStorage.getItem('theme')); ``` -------------------------------- ### Update Item Value Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Example of incrementing a cart count, defaulting to 0 if the key is missing. ```ts const count = appStorage.updateItem('cart-count', (current) => (current ?? 0) + 1); // 1 when the key was previously missing ``` -------------------------------- ### Clear Expired Entries Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Example of setting an item with a TTL and manually triggering cleanup of expired entries. ```ts appStorage.setItem('search-results', ['first', 'second'], { ttl: 5 * 60_000 }); // Later, such as when the application starts again: appStorage.clearExpired(); ``` -------------------------------- ### clear() usage example in app.ts Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Shows clearing ultrastorage entries while leaving localStorage entries untouched. ```typescript appStorage.setItem('theme', 'dark'); localStorage.setItem('analytics-id', 'abc123'); appStorage.clear(); appStorage.getItem('theme'); // null localStorage.getItem('analytics-id'); // 'abc123' ``` -------------------------------- ### Run development commands with vp Source: https://github.com/yangshun/ultrastorage/blob/main/README.md Development workflow commands for this project. `vp test run` runs tests, `vp run test:coverage` enforces 100% runtime coverage, and `vp pack` builds the library. ```sh vp install vp check vp test run vp run test:coverage # enforces 100% runtime coverage vp pack ``` -------------------------------- ### Using key() to retrieve keys by index Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Sets a string key and an array key, then logs the results of key(0), key(1), and key(2). Array keys are returned as fresh arrays. ```ts appStorage.setItem('theme', 'dark'); appStorage.setItem(['users', '42'], 'Alice'); appStorage.key(0); // 'theme' appStorage.key(1); // ['users', '42'] appStorage.key(2); // null ``` -------------------------------- ### Using keys() to enumerate all keys Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Sets a string key and an array key, then logs the result of keys(), which returns an array containing both keys. ```ts appStorage.setItem('theme', 'dark'); appStorage.setItem(['users', '42'], 'Alice'); appStorage.keys(); // ['theme', ['users', '42']] ``` -------------------------------- ### Replace or remove expiration with expiresAt Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/expiration.mdx Pass ttl or expiresAt to replace the deadline, or expiresAt: null to remove it. This example removes expiration from an existing entry. ```ts appStorage.setItem('draft', { title: 'Keep this draft' }, { expiresAt: null }); ``` -------------------------------- ### Create a storage instance with ultrastorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/index.mdx Creates a shared storage instance with a prefix, stores a draft object with a TTL, and subscribes to changes. Demonstrates storing rich values like Date and Set without manual serialization. ```typescript import { createStorage } from 'ultrastorage'; const storage = createStorage({ prefix: 'editor' }); storage.setItem( 'draft:post-42', { title: 'Introducing ultrastorage', updatedAt: new Date(), tags: new Set(['release', 'docs']), }, { ttl: 86_400_000 }, ); storage.subscribe('draft:post-42', refreshPreview); ``` -------------------------------- ### Create shared storage instance with prefix Source: https://github.com/yangshun/ultrastorage/blob/main/docs/getting-started.mdx Define an app-wide singleton storage instance using createStorage with a prefix to avoid key collisions. The prefix is optional but recommended. ```ts import { createStorage } from 'ultrastorage'; // Create an app-wide singleton instance. export const appStorage = createStorage({ // Optional, but highly recommended. The `theme` key will be stored as // `acme:theme`, reducing the likelihood of collisions with third-party code. prefix: 'acme', }); ``` -------------------------------- ### Use shared storage instance Source: https://github.com/yangshun/ultrastorage/blob/main/docs/getting-started.mdx Import the shared instance and use setItem, getItem, and removeItem. getItem returns deserialized values. ```ts import { appStorage } from './lib/app-storage'; appStorage.setItem('theme', 'dark'); appStorage.getItem('theme'); // 'dark' appStorage.removeItem('theme'); ``` -------------------------------- ### Using a schema with getItem Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Validates the persisted value with a Zod schema and infers the type. The example shows retrieving a theme value constrained to 'light' or 'dark'. ```typescript import { z } from 'zod'; const ThemeSchema = z.enum(['light', 'dark']); const theme = appStorage.getItem('theme', { schema: ThemeSchema }); // 'light' | 'dark' | null ``` -------------------------------- ### getOrInit() Method Signature Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md The signature for the getOrInit method, which returns an existing value or initializes a new one using a factory function. ```ts appStorage.getOrInit( key: StorageKey, factory: () => T, options?: StorageOptions, ): T; ``` -------------------------------- ### Initialize a value with getOrInit Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/values.mdx getOrInit('prefs', factory) returns the existing value if present; otherwise it creates, stores, and returns a new value from the provided factory. The factory runs whenever the ordinary read returns null (including stored null, expired entries, and unreadable data). If the factory returns null, it runs again on the next call; expiration options apply only when the value is written. ```TypeScript const prefs = appStorage.getOrInit('prefs', () => ({ theme: 'light', lang: 'en', })); ``` -------------------------------- ### Overlapping prefixes example: acme:admin Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/namespaces.mdx Shows that an instance with prefix 'acme:admin' shares storage scope with the 'acme' instance. Clearing the broader namespace removes entries from both. ```ts import { createStorage } from 'ultrastorage'; const adminStorage = createStorage({ prefix: 'acme:admin' }); adminStorage.setItem('theme', 'dark'); // stored as "acme:admin:theme" appStorage.keys(); // ['admin:theme'] appStorage.clear(); adminStorage.getItem('theme'); // null ``` -------------------------------- ### Use a component-supplied instance with useStorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/react.mdx Demonstrates using `useStorage()` when the caller chooses the instance. The component works with any factory-created ultrastorage instance passed by its parent; keep the supplied instance stable between renders unless you intend to change stores. ```tsx import type { UltraStorage } from 'ultrastorage'; import { useStorage } from 'ultrastorage/react'; export function ThemePicker({ storage }: { storage: UltraStorage }) { const [theme, setTheme] = useStorage(storage, 'theme', { defaultValue: 'light' }); return ( ); } ``` -------------------------------- ### Compare subscriptions between plain localStorage and ultrastorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/index.mdx Shows how plain localStorage requires listening to every storage event and filtering for the cart key, while ultrastorage's subscribe method reacts only when the cart changes. ```javascript event.key === "cart" && syncCart() ``` ```javascript subscribe("cart", syncCart) ``` -------------------------------- ### Enable reactive expiration with useAppStorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/react.mdx Enables reactive expiration for a hook value, updating it to its default (or null) when the entry expires. Timers belong to committed subscriptions and are canceled on unmount, key or storage changes, or disabling the option; SSR and rendering never start timers. ```tsx const [notice] = useAppStorage('notice', { defaultValue: 'Ready', reactiveExpiration: true, }); ``` -------------------------------- ### useStorage with schema and expiresAt in DailyCounter Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/react.mdx Use when the storage instance comes from props or context, allowing the parent to choose where data is stored. The example passes an absolute `expiresAt` to the setter instead of a `ttl`; expiration is lazy, so the component does not rerender at midnight. The schema and default infer `count` and the updater's `previous` as `number`. ```tsx import type { UltraStorage } from 'ultrastorage'; import { useStorage } from 'ultrastorage/react'; import { z } from 'zod'; const CountSchema = z.number().int().nonnegative(); export function DailyCounter({ storage }: { storage: UltraStorage }) { const [count, setCount, removeCount] = useStorage(storage, 'count', { schema: CountSchema, defaultValue: 0, }); function increment() { const midnight = new Date(); midnight.setHours(24, 0, 0, 0); setCount((previous) => previous + 1, { expiresAt: midnight }); } return ( <> ); } ``` -------------------------------- ### Compare plain localStorage with ultrastorage for objects Source: https://github.com/yangshun/ultrastorage/blob/main/docs/index.mdx Shows the difference between manually serializing an object with JSON.stringify and storing it directly with ultrastorage's setItem. The ultrastorage version stores and reads the user as an object. ```javascript JSON.stringify({ name: "Ada" }) ``` ```javascript setItem("user", { name: "Ada" }) ``` -------------------------------- ### createMemoryStorage() Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Creates an in-memory Storage implementation for testing or server-side usage. ```APIDOC ## `createMemoryStorage()` ### Description Returns an in-memory `Storage` implementation. Useful for tests or server-side usage. ### Method `createMemoryStorage()` ### Endpoint `createMemoryStorage()` ### Parameters None. ### Request Example ```ts import { createMemoryStorage, createStorage } from 'ultrastorage'; const testStorage = createStorage({ prefix: 'test', storage: createMemoryStorage(), }); testStorage.setItem('theme', 'dark'); testStorage.getItem('theme'); // 'dark' ``` ### Response #### Success Response Returns a `Storage` object that can be used with `createStorage`. #### Response Example ```ts Storage ``` ``` -------------------------------- ### Configure storage destination with createStorage and createMemoryStorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/destinations.mdx Passes localStorage, sessionStorage, or any Storage-compatible object via the storage option. Uses createMemoryStorage() when window is undefined for server-side rendering. ```ts import { createStorage, createMemoryStorage } from 'ultrastorage'; export const appStorage = createStorage({ prefix: 'acme', storage: typeof window === 'undefined' ? createMemoryStorage() : undefined, }); ``` -------------------------------- ### Compare expiration handling between plain localStorage and ultrastorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/index.mdx Shows how plain localStorage requires manual removal of an OTP after five minutes, while ultrastorage's setItem accepts a TTL option to expire the OTP automatically after five minutes. ```javascript setItem("otp", "4821") ``` ```javascript setItem("otp", 4821, { ttl: 3e5 }) ``` -------------------------------- ### Iterating over keys() snapshot Source: https://github.com/yangshun/ultrastorage/blob/main/docs/reference/storage.md Loops over the snapshot returned by keys() and logs each key. The snapshot is not affected by later writes. ```ts for (const key of appStorage.keys()) { console.log(key); } ``` -------------------------------- ### Compare validation between plain localStorage and ultrastorage Source: https://github.com/yangshun/ultrastorage/blob/main/docs/index.mdx Shows how plain localStorage requires parsing and validating a saved user manually, while ultrastorage's getItem accepts a schema option to validate the saved user while reading it. ```javascript User.parse(JSON.parse(storedUser)) ``` ```javascript getItem("user", { schema: User }) ``` -------------------------------- ### Bind storage with createStorageHook and use it in a Client Component Source: https://github.com/yangshun/ultrastorage/blob/main/docs/guides/react.mdx Create a shared storage instance and a bound hook with createStorageHook() outside components, then use the hook in a Client Component to read and write a key. No provider is required; components using the same key stay in sync across hook writes, ordinary ultrastorage methods, other instances on the same Storage object, and browser storage events from other tabs. ```ts // create instances and bound hooks outside components import { createStorage } from 'ultrastorage'; import { createStorageHook } from 'ultrastorage/react'; export const appStorage = createStorage({ prefix: 'app' }); export const useAppStorage = createStorageHook(appStorage); ``` ```tsx // use a Client Component in an RSC framework 'use client'; import { useAppStorage } from './lib/app-storage'; export function ThemePicker() { const [theme, setTheme, removeTheme] = useAppStorage('theme', { defaultValue: 'light', }); return ( <> ); } ```