Lolly
Otwórz aplikację

Transfer danych - paczka lolly-backup

Wszystko, co gromadzi użytkownik Lolly, znajduje się na jego urządzeniu - bez konta, bez chmury. Paczka transferu danych to sposób, w jaki ta wartość się przemieszcza: eksportujesz ją na jednej instalacji, przenosisz plik dowolną metodą (USB, AirDrop, e-mail do siebie, udział sieciowy) i importujesz na drugiej. Plik jest transportem. Cel może być offline lub online. Nie ma to znaczenia, bo nic nigdy nie łączy się z serwerem.

Dwa przyciski przenoszące całą instalację: Eksportuj moje dane zapisuje jeden plik zip, Import data wczytuje go z powrotem signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBSprawdź samodzielniePobierz podpisany plikDwa przyciski przenoszące całą instalację: Eksportuj moje dane zapisuje jeden plik zip, Import data wczytuje go z powrotem signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBSprawdź samodzielniePobierz podpisany plik

Ta strona to specyfikacja formatu. Instrukcję dla użytkownika końcowego znajdziesz w Znajdź i odzyskaj swoją pracę → Przenieś swoją pracę na inne urządzenie. Implementacja to shells/web/src/data-transfer.ts, a tests/data-transfer.test.ts zabezpiecza kontrakt pełnego cyklu.

Zakres. Paczka niesie dane użytkownika, nie narzędzia z katalogu. Narzędzia i zasoby katalogu są synchronizowane osobno i zakłada się, że już znajdują się na urządzeniu docelowym (w najgorszym razie w nowszej wersji); narzędzia, które użytkownik stworzył sam, podróżują wewnątrz profile.json. Import nigdy nie instaluje ani nie aktualizuje narzędzia z katalogu.

Cele

Koperta

Paczka to zwykły plik .zip. Pobrany plik jest nazwany na cześć osoby, do której należy - LollyTools-<First>-<Last>-<YYYY-MM-DD>-<n>.zip (na przykład LollyTools-Ada-Lovelace-2026-06-26-1.zip) - dzięki czemu folder Downloads z kopiami zapasowymi pozostaje czytelny. Części imienia i nazwiska pochodzą z profilu i są pomijane, gdy nie są ustawione. Brak profilu daje LollyTools-2026-06-26-1.zip, a samo imię daje LollyTools-Ada-2026-06-26-1.zip. Każda część jest sanityzowana do tokenu bezpiecznego dla nazwy pliku (zachowywane są litery i cyfry Unicode, spacje i znaki interpunkcyjne są usuwane, maksymalnie 32 znaki). <n> to sekwencja liczona dziennie, na urządzenie, dzięki czemu powtórzone eksporty tego samego dnia nie kolidują ze sobą i zachowują kolejność. Nazwę tworzy backupFilename() w shells/web/src/data-transfer.ts. Zawartość pliku zip jest identyczna niezależnie od nazwy. W środku:

ŚcieżkaWymaganeZawartość
manifest.jsontakIdentyfikator formatu, wersje, liczniki i integralność poszczególnych części. Pierwsza rzecz, na którą patrzy czytnik.
profile.jsongdy ustawionyCały rekord me użytkownika: imię i nazwisko, kontakt, odniesienie do zdjęcia profilowego i flagi, plus foldery, Kosz, szkice projektów, szablony użytkownika i narzędzia stworzone przez użytkownika, ulubione, ukryte narzędzia, wybór języka i emoji. Odczytywany przez host.profile.
sessions.jsontakKażda zapisana sesja: slot, identyfikator/wersja narzędzia, etykieta, miniatura (data-URL) i pełne dane wejściowe. Odczytywana przez host.state.
assets.jsontakMetadane każdego przesłanego zasobu (obrazy, fonty, tokeny marki, logotypy, zapisane kopie pobrań), z których każdy wskazuje swoje bajty pod assets/blobs/.
assets/blobs/<n>.<ext>na zasóbSurowe bajty zasobu (pliki obrazów i czcionek). Przechowywane bez kompresji (formaty już skompresowane). Rozszerzenie jest kosmetyczne. Rozstrzyga typ MIME w assets.json.
assets/blobs/<n>.c2pagdy obecneWyodrębnione Content Credentials jako dokładne bajty binarne, wskazywane przez _credentialFile w rekordzie zasobu. To nie są klucze podpisujące urządzenia.
design-systems.jsongdy obecneSystemy projektowe stworzone lub dodane na tej instalacji, jako { active, records }. Scalane po identyfikatorze przy imporcie; aktywny wybór paczki ma zastosowanie tylko wtedy, gdy urządzenie docelowe nie ma własnego systemu projektowego.
file-history.jsonopcjonalneWersjonowane migawki zasobów, raporty operacji terminalowych na plikach i kompletne manifesty wsadowe. Część historii ma własną wersję; dostarczana przez wewnętrzny adapter kopii zapasowych fileHistory powłoki.
revision-history.jsonopcjonalne, ręczne kopie zapasoweStabilne identyfikatory kreacji, zachowane checkpointy, miniatury i bieżące szkice odzyskiwania. Dostarczana przez host.state.history.backup tam, gdzie jest obsługiwana.
file-history/versions/na migawkęPoprzednie bajty zasobu i wyodrębnione poświadczenia, niezależnie od tego, czy bieżący zasób nadal istnieje.
file-history/results/na zakończoną operacjęDokładne bajty wyniku. Żaden oryginalny plik wybrany do konwersji nie jest zachowywany ani dołączany.
prefs.jsontakLokalne preferencje należące do użytkownika: theme, sidebarWidth i licznik aktywności ct-metrics.
lolly.txttakCzytelne dla człowieka podsumowanie paczki (liczniki, profil, nazwa pliku) dla każdego, kto otworzy zip bez Lolly. Regenerowane przy każdym eksporcie i rozpoznawane przy imporcie, więc nigdy nie liczy się jako pominięta część. Jest zapisywane po mapie integralności, więc pozostaje poza nią.

Paczka jest celowo zwykłym zipem: przetrwa nienaruszona każdy transport, a każde narzędzie do rozpakowywania może ją sprawdzić.

profile.json to najmniejsza część i ta, którą czytnik widzi jako pierwszą w aplikacji: dane, które twórca wypełnia raz, plus zgoda pozwalająca narzędziom z nich korzystać.

Formularz szczegółów profilu, który staje się plikiem profile.json: imię i nazwisko, dane kontaktowe i zdjęcie portretowe signed by Lollyvector SVG15 paths~1.2k nodes30 groups1 image40 KBSprawdź samodzielniePobierz podpisany plik

manifest.json

{
  "format": "lolly-backup",
  "formatVersion": 3,
  "minReader": 1,
  "app": "lolly",
  "exportedAt": "2026-06-22T09:30:00.000Z",
  "counts": { "profile": true, "sessions": 2, "userAssets": 4, "prefs": 3, "assetVersions": 1, "fileOperations": 1 },
  "integrity": {
    "profile.json": "sha256-…",
    "sessions.json": "sha256-…",
    "assets.json": "sha256-…",
    "assets/blobs/0.bin": "sha256-…",
    "file-history.json": "sha256-…",
    "file-history/versions/0.bin": "sha256-…",
    "file-history/results/0.bin": "sha256-…",
    "prefs.json": "sha256-…"
  }
}
PoleZnaczenie
formatZawsze lolly-backup. Plik bez tego pola jest odrzucany jako "nie jest kopią zapasową Lolly".
formatVersionUkład, w jakim ta paczka została zapisana. Zwiększana przy każdej zmianie zestawu części lub ich kształtu. Czytniki nie blokują importu na jej podstawie.
minReaderMinimalna wersja czytnika wymagana do bezpiecznego zaimportowania tej paczki. To na tym polu czytniki blokują import.
appIdentyfikator aplikacji tworzącej, do celów diagnostycznych.
exportedAtZnacznik czasu ISO utworzenia paczki.
countsTo, co umieścił twórca, do wyświetlania i kontroli poprawności.
integrityOpcjonalne. Mapuje każdą część oprócz manifest.json na skrót w stylu SRI sha256-<base64> jej nieskompresowanych bajtów.

Polityka wersji (kompatybilność w przód)

Podział między formatVersion a minReader pozwala formatowi się rozwijać bez pozostawiania starszych instalacji bez wsparcia:

Praktyczna zasada dla autorów: jeśli każdy istniejący czytnik nadal zachowa się poprawnie, ignorując twoje dodanie, jest to zmiana addytywna - zwiększ formatVersion, zostaw minReader. W przeciwnym razie podnieś minReader.

Integralność

Gdy obecne jest manifest.integrity, czytnik weryfikuje SHA-256 każdej wymienionej części zanim cokolwiek zapisze. Niezgodność ("failed its integrity check") lub brakująca część ("incomplete") przerywa cały import - nie ma częściowego przywracania. Wychwytuje to uszkodzenia, jakie może wprowadzić transport pliku (obcięty AirDrop, bramka e-mail, która ponownie zakodowała załącznik, wadliwy sektor USB).

Integralność jest celowo najlepszym możliwym staraniem: jest zapisywana tylko tam, gdzie dostępne jest Web Crypto (każdy bezpieczny kontekst przeglądarki i nowoczesny Node), i weryfikowana tylko wtedy, gdy obecne są zarówno mapa, jak i Web Crypto. Paczka bez mapy - na przykład sprzed istnienia integralności - importuje się bez zmian. "Nie można zweryfikować" nigdy nie jest traktowane jako "uszkodzone".

Manifest nie wymienia ani samego siebie, ani regenerowanego pliku README lolly.txt. Skróty obejmują części, za które manifest ręczy.

Semantyka importu

Import to scalanie, nigdy pełne zastąpienie:

Zapisane sesje automatycznie ponownie łączą się ze swoimi obrazami: odniesienia do zasobów są przechowywane po identyfikatorze, a most ponownie je rozwiązuje po przywróceniu przesłanych obrazów (i tak musi to zrobić, bo adresy blob: nie przetrwają przeładowania).

Podsumowanie importu zgłasza { profile, sessions, userAssets, prefs, skipped, failedAssets }. failedAssets liczy przesłane zasoby, których nie udało się przywrócić (na przykład pełna pamięć urządzenia). To coś innego niż skipped, które liczy części od nowszego, kompatybilnego wstecz zapisywacza, jakich ta wersja nie rozpoznała. Interfejs pokazuje skipped ("… · N nowszych elementów pominiętych"), więc przywracanie jest szczere co do tego, co zostawiło w tyle.

Gdy obecna jest historia plików, podsumowanie niesie też assetVersions, fileOperations i failedHistory. Wyczerpanie pamięci albo konflikty niezmiennych identyfikatorów mogą spowodować częściowe przywrócenie; interfejs mówi użytkownikowi, aby zachował źródłową kopię zapasową. Synchronizacja w chmurze nie przesuwa swojej zastosowanej rewizji po częściowym albo nieobsługiwanym przywróceniu, więc migawka pozostaje dostępna do ponowienia. Przywracanie nie jest jedną transakcją obejmującą wszystkie magazyny profilu/sesji/zasobów/historii.

Historia kreacji (v3)

Ręczne kopie zapasowe z hosta webowego obsługującego historię zawierają revision-history.json z własnym schematem { version: 1, documents, revisions, recoveries }. Niesie zachowane identyfikatory, kanoniczne migawki danych wejściowych, znaczniki wersji, podglądy rastrowe i osobne szkice edytora. Adapter historii przechwytuje bieżące sesje i ich głowy w jednej transakcji odczytu; sessions.json używa tych samych bieżących migawek dla starszych czytników.

Przywracanie sprawdza SHA-256 i liczby bajtów ładunku, unikalne tożsamości, relacje dokument/głowa, pochodzenie, znaczniki czasu, typy podglądów i limity, zanim zatwierdzi archiwum w jednej transakcji. Skompaktowane odniesienia do rodzica mogą być nieobecne. Istniejąca bieżąca praca nigdy nie jest cicho zastępowana: gdy kreacja występuje po obu stronach, strona niezachowana jako bieżąca staje się chronionym szkicem. Limit transferu archiwum wynoszący 384 MiB jest sprawdzany wprost, a limity pamięci są egzekwowane bez ucinania zachowanych checkpointów. Cała kopia zapasowa nadal używa implementacji ZIP w pamięci i nie jest archiwum strumieniowym.

Podsumowanie dodaje revisions i recoveryDrafts, licząc tylko to, co dodał ten import, oraz added, kept, replaced, copies i hidden, opisujące sposób scalenia każdej kreacji. Powłoka bez tej możliwości przywraca zwykłe sesje i zgłasza część historii jako pominiętą. Historia natywnego systemu plików pozostaje nieobsługiwana, dopóki jej adapter nie dostarczy trwałych transakcji historii. Stan gościa P2P nie ma trwałej historii ani archiwum odzyskiwania.

Osobista synchronizacja migawek celowo wyklucza historię kreacji. Zastosowanie migawki do lokalnego dokumentu niosącego historię zachowuje jego poprzedni stan roboczy jako osobny szkic odzyskiwania i unieważnia token zapisu każdego otwartego edytora. Jego niezmienne checkpointy pozostają na urządzeniu. To chroni lokalną historię podczas zastępowania migawką; nie scala jednoczesnych historii z różnych urządzeń.

Historyczne odniesienia do zasobów są zachowywane, podczas gdy renderowanie nadal rozwiązuje zasoby przez istniejącą bibliotekę celu. To archiwum jeszcze nie gwarantuje dokładnych starych bajtów zasobu ani starych renderów narzędzia. Bajty wersji zasobu i wyniku pliku nadal podróżują przez swoją istniejącą, osobną część kopii zapasowej.

Zapisane wersje i wyniki plików (v2)

Opcjonalna część historii zawiera { version: 2, assetVersions: [...], operations: [...], batches: [...] }; czytniki akceptują też wcześniejszy kształt history-v1 bez batchy. Każda migawka identyfikuje stabilny identyfikator zasobu i dokładną wersję, czas zapisu, długość w bajtach i szesnastkowy SHA-256, plus rekord zasobu, którego _file i opcjonalny _credentialFile wskazują na części binarne. Operacje niosą oryginalne fakty o pliku, żądanie, raport, znaczniki czasu i opcjonalny wynik _file; nazwy backendów przechowywania, uchwyty OPFS i dzierżawy wykonania nie podróżują. Starsze czytniki obsługujące tylko history-v1 odrzucają nową wersję historii przed importem, zamiast po cichu porzucać przynależność do batcha.

Manifesty wsadowe rejestrują każde wybrane źródło przed przetworzeniem, w tym pliki nigdy nieodczytane, anulowanych członków, niepowodzenia rezerwacji miejsca na wynik i przerwaną pracę. Każdy członek ma stabilny identyfikator operacji, odniesienie/fakty źródła, żądaną nazwę wyniku i raport terminalowy. Nieodczytane źródło ma zadeklarowane fakty, nie wymyślony skrót. Import waliduje tożsamość członka i spójność z niesionym raportem operacji. Raporty wsadowe pozostają dostępne, gdy poszczególne wyniki zostały jawnie usunięte, ale potwierdzenie nie oznacza, że jego bajty wyniku są nadal przechowywane.

Starsze czytniki nadal akceptują kopertę v2 (minReader: 1) i przywracają znajome części, licząc nieobsługiwane części historii jako pominięte. Pełne odzyskiwanie historii wymaga powłoki z adapterem fileHistory; to wewnętrzny szew powłoki, nie nowa możliwość HostV1 widoczna dla narzędzi. Prawdziwe przywracanie między dwoma urządzeniami obejmuje lokalna bramka Chromium; akceptacja odzyskiwania na zainstalowanym Tauri/iOS/Androidzie pozostaje osobną sprawą.

Co nie jest przenoszone

Miernik pamięci wylicza ten sam podział. Zapisane sesje, Moje obrazy oraz Wyniki i wersje plików jadą w paczce. Pamięć podręczna zasobów, podglądy narzędzi i przypięcia offline poniżej nich są w pełni odtwarzalne, więc zostają na miejscu.

Miernik pamięci dzielący dane tego urządzenia na nazwane kategorie, z Saved sessions i My images śledzonymi osobno od Asset cache, tutaj na świeżej instalacji, gdzie każda kategoria jest wciąż pusta signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBSprawdź samodzielniePobierz podpisany plikMiernik pamięci dzielący dane tego urządzenia na nazwane kategorie, z Saved sessions i My images śledzonymi osobno od Asset cache, tutaj na świeżej instalacji, gdzie każda kategoria jest wciąż pusta signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBSprawdź samodzielniePobierz podpisany plik

Gwarancja między powłokami

data-transfer.ts odczytuje i zapisuje wyłącznie przez mostek możliwości (host.profile, host.state, host.assets) oraz wspólne preferencje localStorage. Ten sam moduł odczytuje i zapisuje wspólną kopertę na web i Tauri, przez IndexedDB albo pamięć systemu plików. Opcjonalne części historii pojawiają się tylko tam, gdzie dostępny jest odpowiedni adapter; nieobsługiwana część jest zgłaszana jako pominięta przy imporcie. Zestaw testów bezgłowych ćwiczy wspólne części względem mostka w pamięci, podczas gdy transakcje historii mają też testy w prawdziwej przeglądarce.

Dwie powłoki znajdują się poza tą gwarancją, z różnych powodów:

Zarezerwowane punkty rozszerzeń

Koperta jest z założenia manifestem plus zestawem nazwanych części, dzięki czemu nowe rodzaje przenośnych danych będą mogły jechać na niej później bez zmiany łamiącej kompatybilność. Wchodzą jako dodatkowe części (nowe formatVersion, ten sam minReader), a dzisiejszy czytnik pomija to, czego nie rozpoznaje. Nie są one jeszcze zbudowane. Nazwy są tu zarezerwowane, żeby format pozostał spójny, gdy się pojawią.

Wszystko poza tymi zarezerwowanymi nazwami i częściami powyżej jest dla czytnika nieznaną częścią: pozostawioną nietkniętą i policzoną w skipped.

Materiały źródłowe