Transfer de date - pachetul lolly-backup

Tot ce acumulează un utilizator Lolly rămâne pe dispozitivul lui - fără cont, fără cloud. Pachetul de transfer de date este modul în care această valoare se mută: îl exporți pe o instalare, transporți fișierul prin orice mijloc (USB, AirDrop, email către tine însuți, o partajare de rețea) și îl imporți pe alta. Fișierul este transportul. Ținta poate fi offline sau online. Nu contează, pentru că nimic nu comunică vreodată cu un server.

Cele două butoane care mută o instalare întreagă: Export my data scrie un zip, Import data îl citește înapoisigned by Lollyvector SVGVerifică singurGet the signed file12 paths~5.1k nodes12 groups60 KBCele două butoane care mută o instalare întreagă: Export my data scrie un zip, Import data îl citește înapoisigned by Lollyvector SVGVerifică singurGet the signed file12 paths~5.1k nodes12 groups60 KB

Această pagină este specificația formatului. Pentru ghidul pentru utilizatorul final, vezi Using Lolly → Moving to another device. Implementarea este shells/web/src/data-transfer.ts, iar tests/data-transfer.test.ts fixează contractul de round-trip.

Domeniu de aplicare. Un pachet poartă date de utilizator, nu instrumente. Instrumentele și activele din catalog sunt sincronizate separat și se presupune că sunt deja prezente pe țintă (în cel mai rău caz la o versiune mai nouă). Importul nu instalează și nu actualizează niciodată un instrument.

Obiective

Plicul

Un pachet este un simplu .zip. Descărcarea este denumită după persoana căreia îi aparține - LollyTools-<First>-<Last>-<YYYY-MM-DD>-<n>.zip (de exemplu LollyTools-Ada-Lovelace-2026-06-26-1.zip) - astfel încât un folder Descărcări plin de backup-uri rămâne lizibil. Părțile de prenume și nume vin din profil și sunt omise când nu sunt setate. Fără profil rezultă LollyTools-2026-06-26-1.zip, iar doar un prenume dă LollyTools-Ada-2026-06-26-1.zip. Fiecare parte este curățată într-un token sigur pentru nume de fișier (literele/cifrele Unicode păstrate, spațiile/punctuația eliminate, plafonat la 32 de caractere). <n> este o secvență per-zi, per-dispozitiv, astfel încât exporturile repetate în aceeași zi nu se ciocnesc și rămân în ordine. backupFilename() din shells/web/src/data-transfer.ts construiește numele. Conținutul zip-ului este identic indiferent de nume. În interior:

CaleObligatoriuConținut
manifest.jsondaId-ul formatului, versiuni, numărători și integritate per-parte. Primul lucru la care se uită un cititor.
profile.jsondacă e setatÎnregistrarea me a utilizatorului (nume, contact, referință fotografie, flag-uri). Citit prin host.profile.
sessions.jsondaFiecare sesiune salvată: slot, id/versiune instrument, etichetă, miniatură (data-URL) și datele complete de intrare. Citit prin host.state.
assets.jsondaMetadate pentru fiecare activ încărcat (imagini, fonturi, tokenuri de brand), fiecare indicând spre octeții săi din assets/blobs/.
assets/blobs/<n>.<ext>per activOcteții bruți ai activului (fișiere de imagine și font). Stocați necomprimați (formate deja comprimate). Extensia este cosmetică. MIME-ul din assets.json este autoritatea.
prefs.jsondaPreferințe locale deținute de utilizator: theme, sidebarWidth și contorul de activitate ct-metrics.
lolly.txtdaUn rezumat lizibil pentru oameni al pachetului (numărători, profil, nume de fișier) pentru oricine deschide zip-ul fără Lolly. Regenerat la fiecare export și recunoscut la import, astfel încât nu este niciodată numărat ca parte omisă. Este scris după harta de integritate, deci rămâne în afara ei.

Pachetul este un zip simplu în mod intenționat: supraviețuiește intact oricărui transport, iar orice instrument de dezarhivare îl poate inspecta.

profile.json este cea mai mică parte și cea pe care un cititor o vede prima în aplicație: detaliile pe care un producător le completează o singură dată, plus opțiunea de consimțământ care permite instrumentelor să le folosească.

Formularul de detalii Profile care devine profile.json - nume, contact, fotografie și opțiunea de consimțământ alăturisigned by Lollyvector SVGVerifică singurGet the signed file18 paths~2.0k nodes41 groups30 KBFormularul de detalii Profile care devine profile.json - nume, contact, fotografie și opțiunea de consimțământ alăturisigned by Lollyvector SVGVerifică singurGet the signed file18 paths~2.0k nodes41 groups30 KB

manifest.json

{
  "format": "lolly-backup",
  "formatVersion": 1,
  "minReader": 1,
  "app": "lolly",
  "exportedAt": "2026-06-22T09:30:00.000Z",
  "counts": { "profile": true, "sessions": 2, "userAssets": 4, "prefs": 3 },
  "integrity": {
    "profile.json": "sha256-…",
    "sessions.json": "sha256-…",
    "assets.json": "sha256-…",
    "assets/blobs/0.webp": "sha256-…",
    "prefs.json": "sha256-…"
  }
}
CâmpSemnificație
formatÎntotdeauna lolly-backup. Un fișier fără el este respins ca „not a Lolly backup”.
formatVersionStructura cu care a fost scris acest pachet. Crescut la orice schimbare a setului sau formei părților. Cititorii nu se condiționează de el.
minReaderVersiunea minimă de cititor necesară pentru a importa acest pachet în siguranță. Acesta este câmpul de care se condiționează cititorii.
appId-ul aplicației producătoare, pentru diagnosticare.
exportedAtMarca de timp ISO la care a fost creat pachetul.
countsCe a pus scriitorul înăuntru, pentru afișare și verificare de sanitate.
integrityOpțional. Mapează fiecare parte, cu excepția manifest.json, la un digest în stil SRI sha256-<base64> al octeților săi necomprimați.

Politica de versiuni (compatibilitate înainte)

Separarea dintre formatVersion și minReader este ceea ce permite formatului să crească fără a abandona instalările mai vechi:

Regulă practică pentru autori: dacă fiecare cititor existent ar face totuși ce trebuie ignorând adăugarea ta, este aditivă - crește formatVersion, lasă minReader. Altfel, crește minReader.

Integritate

Când manifest.integrity este prezent, un cititor verifică SHA-256 al fiecărei părți listate înainte de a scrie ceva. O nepotrivire („failed its integrity check”) sau o parte lipsă („incomplete”) abandonează întregul import - nu există restaurare parțială. Acest lucru prinde coruperea pe care un transport de fișiere o poate introduce (un AirDrop trunchiat, o poartă de email care a recodat atașamentul, un sector USB defect).

Integritatea este „best-effort” prin design: este scrisă doar acolo unde Web Crypto este disponibil (orice context de browser securizat și Node modern), și verificată doar când atât harta, cât și Web Crypto sunt prezente. Un pachet fără hartă - de exemplu unul dinainte de existența integrității - se importă neschimbat. „Cannot verify” nu este niciodată tratat drept „corrupt”.

Manifestul nu se listează nici pe sine, nici README-ul regenerat lolly.txt. Digest-urile acoperă părțile pentru care manifestul garantează.

Semantica importului

Importul este îmbinare cu suprascriere, niciodată înlocuire totală:

Sesiunile salvate se relegă automat de imaginile lor: referințele către active sunt păstrate după id, iar puntea le rerezolvă după ce imaginile încărcate sunt restaurate (oricum trebuie să o facă, deoarece URL-urile blob: nu supraviețuiesc unei reîncărcări).

Rezumatul importului raportează { profile, sessions, userAssets, prefs, skipped, failedAssets }. failedAssets numără activele încărcate care nu au putut fi restaurate (de exemplu, stocarea dispozitivului plină). Este distinct de skipped, care numără părțile de la un scriitor mai nou, compatibil înainte, pe care această versiune nu le-a recunoscut. UI-ul afișează skipped („… · N newer items skipped”), astfel încât restaurarea este onestă cu privire la ce a lăsat în urmă.

Ce nu călătorește

Contorul de stocare detaliază aceeași separare. Saved sessions și My images călătoresc într-un pachet. Asset cache, previzualizările instrumentelor și fixările offline de sub ele sunt toate re-derivabile, deci rămân în urmă.

Contorul de stocare împărțind datele acestui dispozitiv în categorii denumite, cu Saved sessions și My images urmărite separat de Asset cache, aici pe o instalare nouă unde fiecare categorie este încă goalăsigned by Lollyvector SVGVerifică singurGet the signed file25 paths~4.8k nodes46 groups59 KBContorul de stocare împărțind datele acestui dispozitiv în categorii denumite, cu Saved sessions și My images urmărite separat de Asset cache, aici pe o instalare nouă unde fiecare categorie este încă goalăsigned by Lollyvector SVGVerifică singurGet the signed file25 paths~4.8k nodes46 groups59 KB

Garanția cross-shell

data-transfer.ts citește și scrie exclusiv prin puntea de capabilități (host.profile, host.state, host.assets) și preferințele partajate din localStorage. Deoarece puntea este singura interfață, același modul produce un pachet identic byte cu byte pe fiecare shell, chiar dacă stocarea de dedesubt diferă - IndexedDB pe web, sistemul de fișiere pe Tauri. Shell-urile Tauri reutilizează acest modul neschimbat. Doar implementarea lor host.state diferă. Testul headless verifică ciclul complet de dus-întors față de o punte în memorie, motiv pentru care el le reprezintă pe toate.

Două shell-uri stau în afara acestei garanții, din motive diferite:

Puncte de extensie rezervate

Plicul este, prin proiectare, un manifest plus un set de părți numite, astfel încât noi tipuri de date portabile să îl poată folosi mai târziu fără o schimbare incompatibilă. Ele se integrează ca părți aditive (formatVersion nou, același minReader), iar cititorul de azi sare peste ce nu recunoaște. Acestea sunt pe foaia de parcurs, nu sunt încă implementate. Numele sunt rezervate aici pentru ca formatul să rămână coerent atunci când vor apărea.

Orice se află în afara acestor nume rezervate și a părților de mai sus reprezintă, pentru un cititor, o parte necunoscută: lăsată neatinsă și numărată în skipped.

Referință