Aller au contenu
s3nd.sh

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.

app/api/sync/route.ts
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.

Packagess3nd@s3nd/react

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.