डेटा ट्रांसफ़र - lolly-backup बंडल

Lolly उपयोगकर्ता जो कुछ भी जमा करता है वह उसके डिवाइस पर रहता है - कोई अकाउंट नहीं, कोई क्लाउड नहीं। डेटा-ट्रांसफ़र बंडल इसी मूल्य को हिलाने का तरीका है: इसे एक इंस्टॉल पर एक्सपोर्ट करें, फ़ाइल को किसी भी माध्यम से ले जाएँ (USB, AirDrop, ईमेल-टू-सेल्फ़, एक नेटवर्क शेयर) और दूसरे पर इम्पोर्ट करें। फ़ाइल ही परिवहन है। लक्ष्य डिवाइस ऑफ़लाइन हो या ऑनलाइन। इससे कोई फ़र्क़ नहीं पड़ता, क्योंकि कभी किसी सर्वर से बात नहीं होती।

वे दो बटन जो पूरी इंस्टॉल को स्थानांतरित करते हैं: Export my data एक zip लिखता है, Import data उसे वापस पढ़ता हैsigned by Lollyvector SVGखुद जाँचेंGet the signed file12 paths~5.1k nodes12 groups60 KBवे दो बटन जो पूरी इंस्टॉल को स्थानांतरित करते हैं: Export my data एक zip लिखता है, Import data उसे वापस पढ़ता है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) - ताकि बैकअप्स से भरा Downloads फ़ोल्डर पठनीय बना रहे। पहला और अंतिम भाग प्रोफ़ाइल से आते हैं और सेट न होने पर छोड़ दिए जाते हैं। कोई प्रोफ़ाइल न होने पर LollyTools-2026-06-26-1.zip मिलता है, और अकेला पहला नाम होने पर LollyTools-Ada-2026-06-26-1.zip मिलता है। हर भाग को एक फ़ाइलनाम-सुरक्षित टोकन में सैनिटाइज़ किया जाता है (Unicode अक्षर/अंक रखे जाते हैं, स्पेस/विराम चिह्न हटा दिए जाते हैं, अधिकतम 32 वर्ण)। <n> एक प्रति-दिन, प्रति-डिवाइस क्रम है, ताकि एक ही दिन के बार-बार एक्सपोर्ट टकराएँ नहीं और क्रम में रहें। shells/web/src/data-transfer.ts में backupFilename() यह नाम बनाता है। नाम चाहे जो भी हो, zip की सामग्री समान रहती है। अंदर:

पथआवश्यकसामग्री
manifest.jsonहाँफ़ॉर्मैट id, वर्शन, गिनतियाँ और प्रति-भाग इंटीग्रिटी। पहली चीज़ जो एक रीडर देखता है।
profile.jsonसेट होने परउपयोगकर्ता का me रिकॉर्ड (नाम, संपर्क, हेडशॉट संदर्भ, फ़्लैग)। host.profile के ज़रिए पढ़ा जाता है।
sessions.jsonहाँहर सेव किया गया सेशन: स्लॉट, टूल id/वर्शन, लेबल, थंबनेल (data-URL) और पूरा इनपुट डेटा। host.state के ज़रिए पढ़ा जाता है।
assets.jsonहाँहर अपलोड की गई एसेट (इमेज, फ़ॉन्ट, ब्रांड टोकन) का मेटाडेटा, हर एक assets/blobs/ के तहत अपने बाइट्स की ओर इशारा करता है।
assets/blobs/<n>.<ext>प्रति एसेटकच्चे एसेट बाइट्स (इमेज और फ़ॉन्ट फ़ाइलें)। असंपीड़ित संग्रहीत (पहले से संपीड़ित फ़ॉर्मैट्स)। एक्सटेंशन केवल दिखावटी है। assets.json में MIME ही प्रामाणिक है।
prefs.jsonहाँउपयोगकर्ता-स्वामित्व वाली स्थानीय प्राथमिकताएँ: theme, sidebarWidth और ct-metrics गतिविधि गणना।
lolly.txtहाँबंडल का एक मानव-पठनीय सारांश (गिनतियाँ, प्रोफ़ाइल, फ़ाइलनाम) उस किसी के लिए जो Lolly के बिना zip खोलता है। हर एक्सपोर्ट पर फिर से बनाया जाता है और इम्पोर्ट पर पहचाना जाता है, इसलिए यह कभी छूटे हुए भाग के रूप में नहीं गिना जाता। यह इंटीग्रिटी मैप के बाद लिखा जाता है, इसलिए यह उससे बाहर रहता है।

बंडल जानबूझकर एक सादा zip है: यह किसी भी परिवहन में बरकरार बचता है, और कोई भी अनज़िप टूल इसका निरीक्षण कर सकता है।

profile.json सबसे छोटा भाग है और वह जिसे ऐप में एक रीडर सबसे पहले देखता है: वे विवरण जिन्हें एक निर्माता एक बार भरता है, साथ ही वह ऑप्ट-इन जो टूल को उनका उपयोग करने देता है।

Profile details फ़ॉर्म जो profile.json बनता है - नाम, संपर्क, हेडशॉट और उनके बगल में ऑप्ट-इनsigned by Lollyvector SVGखुद जाँचेंGet the signed file18 paths~2.0k nodes41 groups30 KBProfile details फ़ॉर्म जो 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। इसके बिना फ़ाइल "not a Lolly backup" के रूप में अस्वीकार कर दी जाती है।
formatVersionवह लेआउट जिसके साथ यह बंडल लिखा गया था। भाग-समूह या आकारों में किसी भी बदलाव पर बढ़ाया जाता है। रीडर इस पर गेट नहीं करते।
minReaderन्यूनतम रीडर वर्शन जो इस बंडल को सुरक्षित रूप से इम्पोर्ट करने के लिए आवश्यक है। यही वह फ़ील्ड है जिस पर रीडर गेट करते हैं।
appनिर्माण करने वाला ऐप id, निदान के लिए।
exportedAtबंडल बनाए जाने का ISO टाइमस्टैम्प।
countsलेखक ने क्या डाला, प्रदर्शन और सैनिटी-चेकिंग के लिए।
integrityवैकल्पिक। manifest.json को छोड़कर हर भाग को उसके असंपीड़ित बाइट्स के SRI-शैली sha256-<base64> डाइजेस्ट से मैप करता है।

वर्शन नीति (फ़ॉरवर्ड संगतता)

formatVersion और minReader के बीच का विभाजन ही वह चीज़ है जो फ़ॉर्मैट को पुराने इंस्टॉल्स को अनाथ किए बिना बढ़ने देती है:

लेखकों के लिए अंगूठे का नियम: यदि हर मौजूदा रीडर आपके जोड़े को अनदेखा करके भी सही काम करता रहेगा, तो यह additive है - formatVersion बढ़ाएँ, minReader छोड़ दें। अन्यथा minReader बढ़ाएँ।

इंटीग्रिटी

जब manifest.integrity मौजूद होता है, तो एक रीडर कुछ भी लिखने से पहले हर सूचीबद्ध भाग का SHA-256 सत्यापित करता है। कोई बेमेल ("failed its integrity check") या कोई गायब भाग ("incomplete") पूरे इम्पोर्ट को रद्द कर देता है - कोई आंशिक रीस्टोर नहीं होता। यह उस भ्रष्टाचार को पकड़ता है जो एक फ़ाइल परिवहन ला सकता है (एक कटा हुआ AirDrop, एक ईमेल गेटवे जिसने अटैचमेंट को फिर से एनकोड किया, एक खराब USB सेक्टर)।

इंटीग्रिटी डिज़ाइन से ही बेस्ट-एफ़र्ट है: यह केवल वहीं लिखी जाती है जहाँ Web Crypto उपलब्ध है (हर सुरक्षित ब्राउज़र संदर्भ और आधुनिक Node), और केवल तभी सत्यापित होती है जब मैप और Web Crypto दोनों मौजूद हों। बिना मैप वाला बंडल - उदाहरण के लिए इंटीग्रिटी अस्तित्व में आने से पहले का कोई बंडल - बिना बदलाव के इम्पोर्ट हो जाता है। "Cannot verify" को कभी "corrupt" के रूप में नहीं लिया जाता।

मैनिफ़ेस्ट न तो अपने आप को सूचीबद्ध करता है और न ही फिर से बनाए गए lolly.txt README को। डाइजेस्ट उन्हीं भागों को कवर करते हैं जिनकी मैनिफ़ेस्ट गारंटी देता है।

इम्पोर्ट सिमेंटिक्स

इम्पोर्ट मर्ज-ओवरराइट है, कभी सब कुछ बदलना नहीं:

सेव किए गए सेशन अपने-आप अपनी इमेज से फिर से जुड़ जाते हैं: एसेट संदर्भ id से रखे जाते हैं, और अपलोड की गई इमेज रीस्टोर होने के बाद ब्रिज उन्हें फिर से हल करता है (इसे वैसे भी करना ही होता है, क्योंकि blob: URLs रीलोड में नहीं बचते)।

इम्पोर्ट सारांश { profile, sessions, userAssets, prefs, skipped, failedAssets } रिपोर्ट करता है। failedAssets उन अपलोड की गई एसेट्स की गिनती करता है जिन्हें रीस्टोर नहीं किया जा सका (जैसे डिवाइस स्टोरेज भरा होना)। यह skipped से अलग है, जो एक फ़ॉरवर्ड-संगत नए लेखक के उन भागों की गिनती करता है जिन्हें इस बिल्ड ने नहीं पहचाना। UI skipped को सामने लाता है ("… · N newer items skipped"), ताकि रीस्टोर इस बारे में ईमानदार रहे कि उसने क्या पीछे छोड़ा।

क्या यात्रा नहीं करता

स्टोरेज मीटर उसी विभाजन को वस्तुओं में बाँटता है। सेव किए गए सेशन और 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 केवल कैपेबिलिटी ब्रिज (host.profile, host.state, host.assets) और साझा localStorage प्रेफ़्स के माध्यम से पढ़ता और लिखता है। चूँकि ब्रिज ही एकमात्र सीम है, वही मॉड्यूल हर शेल पर बाइट-फ़ॉर-बाइट समान बंडल बनाता है, भले ही नीचे का स्टोरेज अलग हो - वेब पर IndexedDB, Tauri पर फ़ाइल सिस्टम। Tauri शेल इस मॉड्यूल को बिना बदलाव के फिर से इस्तेमाल करते हैं। केवल उनका host.state कार्यान्वयन अलग होता है। हेडलेस टेस्ट पूरे राउंड-ट्रिप को एक इन-मेमोरी ब्रिज के विरुद्ध चलाता है, इसीलिए यह इन सबका प्रतिनिधित्व करता है।

दो शेल उस गारंटी से बाहर हैं, अलग-अलग वजहों से:

सुरक्षित एक्सटेंशन पॉइंट

एनवेलप जानबूझकर एक मेनिफ़ेस्ट और नामित भागों का एक सेट है, ताकि नए तरह का पोर्टेबल डेटा बाद में बिना किसी ब्रेकिंग बदलाव के इस पर सवार हो सके। ये अतिरिक्त भागों के रूप में शामिल होते हैं (नया formatVersion, वही minReader), और आज का रीडर जो नहीं पहचानता उसे छोड़ देता है। ये रोडमैप पर हैं, अभी लागू नहीं हुए हैं। नाम यहाँ सुरक्षित रखे गए हैं ताकि जब ये आएँ तो फ़ॉर्मैट सुसंगत बना रहे।

इन सुरक्षित नामों और ऊपर दिए गए भागों के अलावा कुछ भी रीडर के लिए एक अज्ञात भाग है: बिना छेड़े छोड़ दिया जाता है और skipped में गिना जाता है।

संदर्भ