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.