Lolly
Отвори приложението

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

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

Двата бутона, които местят цяла инсталация: Export my data записва един zip, Import data го зарежда обратно signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBПровери самВземи подписания файлДвата бутона, които местят цяла инсталация: Export my data записва един zip, Import data го зарежда обратно signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBПровери самВземи подписания файл

Тази страница е спецификацията на формата. За описание за крайния потребител виж Намери и възстанови работата си → Премести работата си на друго устройство. Реализацията е в shells/web/src/data-transfer.ts, а tests/data-transfer.test.ts фиксира договора за пренасяне на данните напред-назад.

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

Цели

Обвивката

Пакетът е обикновен .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 е меродавен.
assets/blobs/<n>.c2paкогато е наличноИзвлечени Content Credentials като точни двоични байтове, посочени от _credentialFile в записа на актива. Те не са ключове за подписване на устройството.
design-systems.jsonкогато е наличноДизайн системите, направени или добавени на тази инсталация, като { active, records }. Сливат се по id при внасяне; активният избор на пакета важи само когато целта няма собствена дизайн система.
file-history.jsonпо изборВерсионирани снимки на активи, крайни отчети за файлови операции и пълни манифести на batch. Частта за история има собствена версия; осигурена е от вътрешния адаптер за резервно копиране fileHistory на обвивката.
revision-history.jsonпо избор, ръчни резервни копияСтабилни ID на творения, запазени контролни точки, миниатюри и текущи чернови за възстановяване. Осигурена чрез host.state.history.backup, където се поддържа.
file-history/versions/за всяка снимкаПредишни байтове на актив и извлечени credentials, независимо дали текущият актив все още съществува.
file-history/results/за всяка завършена операцияТочни байтове на изхода. Никой оригинален файл, избран за конвертиране, не се запазва или включва.
prefs.jsonдаЛокални предпочитания, притежавани от потребителя: theme, sidebarWidth и брояча на активност ct-metrics.
lolly.txtдаЧетимо от човек резюме на пакета (брой елементи, профил, име на файл) за всеки, който отваря zip-а без Lolly. Прегенерира се при всеки експорт и се разпознава при внасяне, така че никога не се брои за пропусната част. Записва се след картата на цялостността, така че остава извън нея.

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

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

Формулярът с детайли на профила, който става profile.json: име, данни за контакт и портретна снимка signed by Lollyvector SVG15 paths~1.2k nodes30 groups1 image40 KBПровери самВземи подписания файл

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-…"
  }
}
ПолеЗначение
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 по-нови елемента пропуснати“), така че възстановяването е честно относно това, което е оставило зад себе си.

Когато е налична историята на файлове, резюмето носи и assetVersions, fileOperations и failedHistory. Изчерпване на хранилището или конфликти на неизменни ID могат да причинят частично възстановяване; интерфейсът казва на потребителя да запази изходното резервно копие. Облачната синхронизация не напредва приложената си ревизия след частично или неподдържано възстановяване, така че снимката остава налична за повторен опит. Възстановяването не е една единствена транзакция за всички хранилища на профил/сесия/актив/история.

История на творенията (v3)

Ръчните резервни копия от уеб хост, поддържащ история, включват revision-history.json със собствена схема { version: 1, documents, revisions, recoveries }. Тя носи запазените ID, каноничните снимки на входните данни, версийните печати, растерните превюта и отделните чернови на автора. Адаптерът за история улавя текущите сесии и техните върхове в една транзакция за четене; sessions.json използва същите тези текущи снимки за по-стари четци.

Възстановяването проверява SHA-256 и броя байтове на полезния товар, уникалните идентичности, връзките документ/връх, произхода, времевите печати, типовете превюта и лимитите, преди да приложи архива в една транзакция. Компресирани препратки към родители може да липсват. Съществуващата текуща работа никога не се заменя мълчаливо: когато творение е налично от двете страни, страната, която не е запазена като текуща, става защитена чернова. Лимитът от 384 MiB за пренос на архива се проверява изрично, а лимитите за съхранение се налагат, без да съкращават запазените контролни точки. Цялостното резервно копие все още използва in-memory ZIP реализация и не е стрийминг архив.

Резюмето добавя revisions и recoveryDrafts, като брои само това, което е добавил този импорт, и added, kept, replaced, copies и hidden - как е слято всяко творение. Обвивка без тази възможност възстановява обикновени сесии и отчита частта за история като пропусната. Историята на native файловата система остава неподдържана, докато нейният адаптер не осигури трайни транзакции за история. Гост състоянието на P2P няма трайна история или архив за възстановяване.

Личната синхронизация на снимки изрично изключва историята на творенията. Прилагането на снимка към локален документ с история запазва предишното му работно състояние като отделна чернова за възстановяване и анулира write токена на всеки отворен редактор. Неговите неизменни контролни точки остават на устройството. Това защитава локалната история по време на замяна със снимка; не слива историите на едновременни устройства.

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

Запазени версии и резултати от файлове (v2)

Незадължителната част за история съдържа { version: 2, assetVersions: [...], operations: [...], batches: [...] }; четците приемат и по-ранната форма history-v1 без batches. Всяка снимка идентифицира стабилния ID на актива и точната версия, времето на запазване, дължината в байтове и hex SHA-256, плюс запис на актив, чиито _file и незадължителен _credentialFile сочат към бинарни части. Операциите носят оригиналните факти за файла, заявката, отчета, времевите печати и незадължителен резултат _file; имената на бекенда за съхранение, дескрипторите на OPFS и лизингите за изпълнение не пътуват. По-стари четци, поддържащи само history-v1, отказват новата версия на историята преди внасяне, вместо мълчаливо да изпуснат членството в batch.

Манифестите на batch записват всеки избран източник преди обработка, включително файлове, които никога не са прочетени, отменени членове, неуспехи при резервиране на място за резултат и прекъсната работа. Всеки член има стабилен ID на операция, препратка/факти за източника, заявено име на изхода и краен отчет. Непрочетен източник има декларирани факти, а не измислен дайджест. Внасянето валидира идентичността на члена и съгласуваността с всеки пренесен отчет за операция. Отчетите за batch остават налични, когато отделни резултати са изрично премахнати, но разписка не означава, че байтовете на нейния изход все още се съхраняват.

По-старите четци все още приемат обвивката v2 (minReader: 1) и възстановяват познатите части, като броят неподдържаните части на историята като пропуснати. Пълното възстановяване на историята изисква обвивка с адаптера fileHistory; това е вътрешен за обвивката шев, не нова възможност на HostV1, обърната към инструментите. Истинското възстановяване между две устройства е покрито от локалния Chromium gate; приемането на възстановяване в инсталирани Tauri/iOS/Android остава отделно.

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

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

Индикаторът за съхранение, разделящ данните на това устройство на именувани категории, със Saved sessions и My images проследени отделно от Asset cache, тук на прясна инсталация, където всяка категория все още е празна signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBПровери самВземи подписания файлИндикаторът за съхранение, разделящ данните на това устройство на именувани категории, със Saved sessions и My images проследени отделно от Asset cache, тук на прясна инсталация, където всяка категория все още е празна signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBПровери самВземи подписания файл

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

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

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

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

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

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

Справочник