Прехвърляне на данни - пакетът lolly-backup

Всичко, което потребител на Lolly натрупва, живее на неговото устройство - без акаунт, без облак. Пакетът за прехвърляне на данни е начинът, по който тази стойност се движи: изнеси я на една инсталация, пренеси файла с каквото и да е средство (USB, AirDrop, имейл до себе си, споделена мрежова папка) и внеси я на друга. Файлът е транспортът. Целта може да е офлайн или онлайн. Няма значение, защото нищо никога не комуникира със сървър.

Двата бутона, които местят цяла инсталация: Изнеси моите данни записва един zip, Внеси данни го зарежда обратноsigned by Lollyvector SVGПровери самGet the signed file12 paths~5.1k nodes12 groups60 KBДвата бутона, които местят цяла инсталация: Изнеси моите данни записва един zip, Внеси данни го зарежда обратноsigned by Lollyvector SVGПровери самGet the signed file12 paths~5.1k nodes12 groups60 KB

Тази страница е спецификацията на формата. За описание за крайния потребител виж Using Lolly → Moving to another device. Реализацията е в shells/web/src/data-transfer.ts, а tests/data-transfer.test.ts фиксира договора за пренасяне на данните напред-назад.

Обхват. Пакетът носи потребителски данни, не инструменти. Инструментите и активите от каталога се синхронизират отделно и се приема, че вече присъстват на целта (в най-лошия случай в по-нова версия). Внасянето никога не инсталира или обновява инструмент.

Цели

Обвивката

Пакетът е обикновен .zip. Изтегленият файл е именуван на човека, на когото принадлежи - LollyTools-<First>-<Last>-<YYYY-MM-DD>-<n>.zip (например LollyTools-Ada-Lovelace-2026-06-26-1.zip) - така че папката с изтегляния, съдържаща резервни копия, остава четлива. Частите за собствено и фамилно име идват от профила и се пропускат, ако не са зададени. Липсващ профил дава LollyTools-2026-06-26-1.zip, а само собствено име дава LollyTools-Ada-2026-06-26-1.zip. Всяка част се пречиства до безопасен за файлово име токен (запазват се Unicode букви/цифри, премахват се интервали/пунктуация, ограничение от 32 знака). <n> е последователност за ден и устройство, така че повторни експорти в един и същи ден не се сблъскват и остават подредени. backupFilename() в shells/web/src/data-transfer.ts изгражда името. Съдържанието на zip файла е еднакво независимо от името. Вътре:

ПътЗадължителенСъдържание
manifest.jsonдаId на формата, версии, брой елементи и цялостност по части. Първото нещо, което чете четецът.
profile.jsonако е зададенЗаписът me на потребителя (име, контакт, връзка към снимка, флагове). Чете се чрез host.profile.
sessions.jsonдаВсяка запазена сесия: слот, id/версия на инструмента, етикет, миниатюра (data-URL) и пълни входни данни. Чете се чрез host.state.
assets.jsonдаМетаданни за всеки качен актив (изображения, шрифтове, брандови токени), всяко сочещо към своите байтове под assets/blobs/.
assets/blobs/<n>.<ext>по активСуровите байтове на актива (файлове с изображения и шрифтове). Съхраняват се некомпресирани (вече компресирани формати). Разширението е козметично. MIME типът в assets.json е меродавен.
prefs.jsonдаЛокални предпочитания, притежавани от потребителя: theme, sidebarWidth и брояча на активност ct-metrics.
lolly.txtдаЧетимо от човек резюме на пакета (брой елементи, профил, име на файл) за всеки, който отваря zip-а без Lolly. Прегенерира се при всеки експорт и се разпознава при внасяне, така че никога не се брои за пропусната част. Записва се след картата на цялостността, така че остава извън нея.

Пакетът е обикновен zip нарочно: оцелява всеки транспорт непокътнат, а всеки инструмент за разархивиране може да го инспектира.

profile.json е най-малката част и тази, която потребителят вижда пръв в приложението: данните, попълнени веднъж от него, плюс опцията, която позволява на инструментите да ги ползват.

Формулярът с данните на профила, който се превръща в profile.json - име, контакт, снимка и опцията до тяхsigned by Lollyvector SVGПровери самGet the signed file18 paths~2.0k nodes41 groups30 KBФормулярът с данните на профила, който се превръща в profile.json - име, контакт, снимка и опцията до тяхsigned by Lollyvector SVGПровери самGet 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-…"
  }
}
ПолеЗначение
formatВинаги lolly-backup. Файл без него се отхвърля като „не е резервно копие на Lolly“.
formatVersionОформлението, с което е записан този пакет. Увеличава се при всяка промяна на набора или формата на частите. Четците не се базират на него.
minReaderМинималната версия на четеца, необходима за безопасно внасяне на този пакет. Това е полето, на което се базират четците.
appId на произвеждащото приложение, за диагностика.
exportedAtISO времеви печат на създаването на пакета.
countsКакво е сложил писателят, за показване и проверка за здравина.
integrityПо избор. Свързва всяка част освен manifest.json с дайджест във формат SRI - sha256-<base64> - на нейните некомпресирани байтове.

Политика за версии (обратна съвместимост напред)

Разделянето между formatVersion и minReader е това, което позволява на формата да расте, без да изолира по-стари инсталации:

Правило на палеца за автори: ако всеки съществуващ четец все пак ще постъпи правилно, като игнорира добавката ти, тя е добавяща - увеличи formatVersion, остави minReader. В противен случай вдигни minReader.

Цялостност

Когато manifest.integrity присъства, четец проверява SHA-256 на всяка изброена част преди да запише каквото и да е. Несъответствие („не премина проверката за цялостност“) или липсваща част („непълен“) прекратява цялото внасяне - няма частично възстановяване. Това улавя повредата, която транспортът на файл може да внесе (орязан AirDrop, имейл шлюз, който е прекодирал прикачения файл, лош USB сектор).

Цялостността е по замисъл best-effort: записва се само там, където Web Crypto е налична (всеки сигурен контекст на браузър и съвременен Node), и се проверява само когато и картата, и Web Crypto присъстват. Пакет без картата - например такъв отпреди появата на цялостността - се внася непроменен. „Не може да се провери“ никога не се третира като „повреден“.

Манифестът не изброява нито себе си, нито прегенерирания README lolly.txt. Дайджестите покриват частите, за които манифестът гарантира.

Семантика на внасянето

Внасянето е сливане с презаписване, никога пълна замяна:

Запазените сесии се повторно свързват към своите изображения автоматично: препратките към активи се пазят по id, а мостът ги преразрешава наново, след като качените изображения бъдат възстановени (задължително, тъй като URL адресите blob: не оцеляват при презареждане).

Резюмето на внасянето отчита { profile, sessions, userAssets, prefs, skipped, failedAssets }. failedAssets брои качени активи, които не са могли да бъдат възстановени (например пълно устройство за съхранение). Различно е от skipped, което брои части от по-нов писател с обратна съвместимост, които тази версия не е разпознала. Интерфейсът показва skipped („… · N по-нови елемента пропуснати“), така че възстановяването е честно относно това, което е оставило зад себе си.

Какво не пътува

Индикаторът за съхранение изброява същото разделение. Запазените сесии и My images пътуват в пакет. Кешът на активите, преглед на инструментите и офлайн закачените под тях всички са възстановими наново, така че остават извън него.

Индикаторът за съхранение, разделящ данните на това устройство на именувани категории, със Saved sessions и My images проследени отделно от Asset cache, тук на прясна инсталация, където всяка категория все още е празнаsigned by Lollyvector SVGПровери самGet the signed file25 paths~4.8k nodes46 groups59 KBИндикаторът за съхранение, разделящ данните на това устройство на именувани категории, със Saved sessions и My images проследени отделно от Asset cache, тук на прясна инсталация, където всяка категория все още е празнаsigned by Lollyvector SVGПровери самGet the signed file25 paths~4.8k nodes46 groups59 KB

Гаранция между обвивки

data-transfer.ts чете и записва изключително през capability bridge (host.profile, host.state, host.assets) и споделените localStorage предпочитания. Тъй като bridge-ът е единствената точка на допир, един и същ модул произвежда байт-идентичен пакет на всяка обвивка, дори когато съхранението отдолу е различно - IndexedDB в уеб, файловата система в Tauri. Обвивките на Tauri преизползват този модул непроменен. Различава се само тяхната реализация на host.state. Headless тестът упражнява пълния round-trip срещу in-memory bridge, затова той представя всички тях.

Две обвивки остават извън тази гаранция, по различни причини:

Запазени точки за разширение

Обвивката е манифест плюс набор от именувани части по замисъл, така че по-нови видове преносими данни да могат да я използват по-късно без пробиваща промяна. Те се вграждат като допълнителни части (нов formatVersion, същия minReader), а днешният четец пропуска това, което не разпознава. Това са неща от пътната карта, още не са реализирани. Имената са запазени тук, за да остане форматът съгласуван, когато бъдат добавени.

Всичко извън тези запазени имена и частите по-горе е за четеца непозната част: оставя се недокоснато и се брои в skipped.

Справочник