createHandoff
Hand a value — a File, a Blob, anything structured-cloneable — from one page to the next on the same origin.
A File the user picked on page A cannot travel to page B. It will not fit in a URL and is not serialisable; sessionStorage only takes strings. IndexedDB stores structured-cloneable values as they are, so page A stashes the value and navigates, and page B takes it out.
API
createHandoff(options)
| Parameter | Description | Type | Default |
|---|---|---|---|
dbName | Database name; both sides must agree on it | string | Required |
storeName | Object store name, created on first open | string | 'files' |
key | Key the single pending value is stored under | string | 'pending' |
Return
| Method | Description |
|---|---|
put(value) | Store a value for the next page. false when it could not store |
take() | Take the pending value and delete it. null when nothing is pending |
Example
Landing page hands a file to the app
import { createHandoff } from 'ranuts';
const handoff = createHandoff({ dbName: 'document-handoff' });
input.addEventListener('change', async () => {
await handoff.put(input.files[0]);
location.href = '/app?open=local';
});The app takes it
import { createHandoff, queryFlag } from 'ranuts';
const handoff = createHandoff({ dbName: 'document-handoff' });
if (queryFlag('open')) {
const file = await handoff.take();
if (file) openDocument(file); // null on a reload — the value is consumed
}Notes
Reading is destructive.
take()deletes the value in the same transaction that reads it. That is what stops a page reload from re-opening the same file, and what makes a stale?open=localURL find nothing.Two tabs cannot both win. Because the read and the delete share one transaction, a race between tabs hands the value to exactly one of them.
putresolves on commit, not on the write request. The value is only durable once the transaction commits — and the page usually navigates away immediately after.Failures are quiet. A missing or blocked IndexedDB (SSR, private mode, a third-party frame) makes
putresolvefalseandtakeresolvenull. A page that merely tried to hand something over must not break because storage was unavailable.The store is created at version 1 by whichever side opens the database first; the other finds it already there.
One value at a time. This is a handoff, not a queue — a second
putoverwrites the pending value. UseWebDBwhen you need real storage.