Cas d’usage
Migrer une app sur un nouvel appareil
Une app local-first sans comptes. Un code sur l’ancien téléphone, tapé sur le nouveau, et toute la base de données suit.
import { store, SCHEMA_VERSION } from '@/lib/store'
export async function POST(request: Request) {
const state = await request.json()
const code = store.codes.create()
await store.putSnapshot(code, state, {
app: 'notes',
version: SCHEMA_VERSION,
device: request.headers.get('user-agent') ?? undefined,
expiresIn: 60 * 60,
ifAbsent: true,
})
return Response.json({ code })
}La situation
Ce qui se passe vraiment.
Le problème
L’utilisateur a un nouveau téléphone. L’app sur l’ancien contient tout, dans IndexedDB, et il n’y a aucun compte où se connecter parce que l’app n’en a jamais eu besoin. IndexedDB ne quitte pas le navigateur dans lequel il a été écrit.
Ce que s3nd y fait
L’ancien appareil exporte ses object stores, les poste à votre API, et reçoit un code de huit caractères. Le nouvel appareil tape le code, voit ce qu’il s’apprête à restaurer, et remplace sa base vide en une seule transaction. Le snapshot expire dans l’heure et le code est brûlé en cas de succès.
À surveiller
Les choses faciles à rater.
Confirmer avant de remplacer
Renvoyez createdAt et device depuis la lecture, et affichez-les. L’erreur la plus courante est de restaurer sur l’appareil qui avait déjà les données.
Versionner le snapshot
Passez maxVersion à la lecture. Un snapshot issu d’une version plus récente de l’app échoue avec une erreur claire au lieu d’atterrir dans une version qui va le mal lire.
Brûler le code
Un DELETE après un import réussi est le chemin propre ; l’expiration est le filet de sécurité. Les deux tiennent en une ligne.
Voir aussi
D’autres formes de la même primitive.
Déposez un fichier. Donnez le code.
Pointez-le sur le bucket que vous payez déjà. Rien à déployer, aucune inscription, personne au milieu.