একজন Lolly ব্যবহারকারী যা কিছু সঞ্চয় করেন তা তাদের ডিভাইসেই থাকে - কোনো অ্যাকাউন্ট নেই, কোনো ক্লাউড নেই। data-transfer বান্ডেল হলো সেই মূল্য স্থানান্তরের উপায়: এটি একটি ইনস্টলে এক্সপোর্ট করুন, যেকোনো মাধ্যমে ফাইলটি বহন করুন (USB, AirDrop, ইমেইল-টু-সেলফ, একটি নেটওয়ার্ক শেয়ার) এবং অন্যটিতে ইমপোর্ট করুন। ফাইলটিই পরিবহন। টার্গেট অফলাইন বা অনলাইন হতে পারে। এতে কোনো পার্থক্য হয় না, কারণ কখনো কোনো সার্ভারের সাথে যোগাযোগ হয় না।
signed by Lollyvector SVG৯ paths~4.9k nodes১১ groups৫৬ KBনিজেই যাচাই করুনস্বাক্ষরিত ফাইলটি নিন
signed by Lollyvector SVG৯ paths~4.9k nodes১১ groups৫৬ KBনিজেই যাচাই করুনস্বাক্ষরিত ফাইলটি নিন
এই পৃষ্ঠাটি ফরম্যাট স্পেক। এন্ড-ইউজার ওয়াকথ্রুর জন্য দেখুন আপনার কাজ খুঁজুন ও ফিরে পান → আপনার কাজ অন্য ডিভাইসে নিয়ে যান। ইমপ্লিমেন্টেশনটি হলো shells/web/src/data-transfer.ts, এবং tests/data-transfer.test.ts round-trip কন্ট্র্যাক্টকে পিন করে।
Scope. একটি বান্ডেল ব্যবহারকারীর ডেটা বহন করে, ক্যাটালগ টুল নয়। ক্যাটালগ টুল এবং ক্যাটালগ অ্যাসেট আলাদাভাবে সিঙ্ক করা হয় এবং ধরে নেওয়া হয় যে সেগুলো টার্গেটে ইতিমধ্যে উপস্থিত (সবচেয়ে খারাপ ক্ষেত্রে উচ্চতর ভার্সনে); ব্যবহারকারীর নিজের বানানো টুল
profile.json-এর ভেতরে ভ্রমণ করে। ইমপোর্ট করা কখনো কোনো ক্যাটালগ টুল ইনস্টল বা আপগ্রেড করে না।
লক্ষ্য
- One format, every shell. ওয়েব PWA, Tauri ডেস্কটপ/মোবাইল অ্যাপ এবং ভবিষ্যৎ শেলগুলো একই এনভেলপ ও সমর্থিত পার্ট স্কিমা শেয়ার করে। ঐচ্ছিক পার্ট প্রতিটি শেলের সক্ষমতার উপর নির্ভর করে; অসমর্থিত পার্ট রিপোর্ট করা হয়। প্রতিটি capability bridge তার নিজস্ব স্টোরেজ অ্যাডাপ্টার দেয়।
- Survives the trip. পরিবহনে বিকৃত বা ছেঁটে যাওয়া একটি বান্ডেল ইমপোর্টে স্পষ্টভাবে ব্যর্থ হয়, কখনো অর্ধেক-পুনরুদ্ধার করে না।
- Outlives this version. একটি পুরনো অ্যাপ এখনও একটি নতুন বান্ডেলের স্বীকৃত অংশগুলো ইমপোর্ট করতে পারে। প্রকৃতভাবে ব্রেকিং একটি ফরম্যাট পরিষ্কারভাবে প্রত্যাখ্যাত হয়।
- Safe to merge. ইতিমধ্যে ব্যবহৃত একটি ইনস্টলে ইমপোর্ট করা বান্ডেলে না থাকা কিছুই কখনো মুছে দেয় না।
এনভেলপ
একটি বান্ডেল একটি সাধারণ .zip। ডাউনলোডটির নাম যার জন্য এটি তার নামে - LollyTools-<First>-<Last>-<YYYY-MM-DD>-<n>.zip (উদাহরণস্বরূপ LollyTools-Ada-Lovelace-2026-06-26-1.zip) - যাতে ব্যাকআপের Downloads ফোল্ডার সুপাঠ্য থাকে। First এবং Last অংশ প্রোফাইল থেকে আসে এবং সেট না থাকলে বাদ দেওয়া হয়। কোনো প্রোফাইল না থাকলে LollyTools-2026-06-26-1.zip পাওয়া যায়, এবং শুধু একটি প্রথম নাম থাকলে LollyTools-Ada-2026-06-26-1.zip পাওয়া যায়। প্রতিটি অংশ একটি ফাইলনেম-সেফ টোকেনে স্যানিটাইজ করা হয় (ইউনিকোড অক্ষর/সংখ্যা রাখা হয়, স্পেস/যতিচিহ্ন সরানো হয়, 32 অক্ষরে সীমাবদ্ধ)। <n> একটি প্রতি-দিন, প্রতি-ডিভাইস সিকোয়েন্স, তাই একই দিনে বারবার এক্সপোর্ট করলে সংঘর্ষ হয় না এবং ক্রম বজায় থাকে। shells/web/src/data-transfer.ts-এর backupFilename() নামটি তৈরি করে। নাম যাই হোক না কেন, zip-এর বিষয়বস্তু অভিন্ন থাকে। ভেতরে:
| পাথ | আবশ্যক | বিষয়বস্তু |
|---|---|---|
manifest.json | হ্যাঁ | ফরম্যাট id, ভার্সন, গণনা এবং প্রতি-অংশ integrity। রিডার সর্বপ্রথম যা দেখে। |
profile.json | সেট থাকলে | ব্যবহারকারীর সম্পূর্ণ me রেকর্ড: নাম, যোগাযোগ, হেডশট রেফ ও ফ্ল্যাগ, সাথে ফোল্ডার, Trash, প্রজেক্ট ব্লুপ্রিন্ট, ইউজার টেমপ্লেট ও ইউজার-নির্মিত টুল, ফেভারিট, লুকানো টুল, ভাষা ও ইমোজি বাছাই। host.profile দিয়ে পড়া হয়। |
sessions.json | হ্যাঁ | প্রতিটি সেভ করা সেশন: স্লট, টুল id/ভার্সন, লেবেল, থাম্বনেইল (data-URL) এবং সম্পূর্ণ ইনপুট ডেটা। host.state দিয়ে পড়া হয়। |
assets.json | হ্যাঁ | প্রতিটি আপলোড করা অ্যাসেটের (ইমেজ, ফন্ট, ব্র্যান্ড টোকেন, লোগো, ডাউনলোডের সেভ করা কপি) মেটাডেটা, যেগুলো assets/blobs/-এর অধীনে তাদের বাইট নির্দেশ করে। |
assets/blobs/<n>.<ext> | প্রতি অ্যাসেটে | কাঁচা অ্যাসেট বাইট (ইমেজ এবং ফন্ট ফাইল)। আনকমপ্রেসড অবস্থায় সংরক্ষিত (ইতিমধ্যে-কমপ্রেসড ফরম্যাট)। এক্সটেনশনটি নান্দনিক। assets.json-এর MIME-ই কর্তৃত্বপূর্ণ। |
assets/blobs/<n>.c2pa | উপস্থিত থাকলে | অ্যাসেট রেকর্ডে _credentialFile দ্বারা রেফারেন্স করা, প্রকৃত বাইনারি বাইট হিসেবে এক্সট্র্যাক্ট করা Content Credentials। এগুলো ডিভাইস সাইনিং কী নয়। |
design-systems.json | উপস্থিত থাকলে | এই ইনস্টলে বানানো বা যোগ করা ডিজাইন সিস্টেম, { active, records } হিসেবে। ইমপোর্টে id দিয়ে মার্জ করা হয়; বান্ডেলের সক্রিয় পছন্দ তখনই প্রযোজ্য যখন টার্গেটের নিজস্ব কোনো ডিজাইন সিস্টেম নেই। |
file-history.json | ঐচ্ছিক | ভার্সনযুক্ত অ্যাসেট স্ন্যাপশট, টার্মিনাল ফাইল-অপারেশন রিপোর্ট এবং সম্পূর্ণ ব্যাচ ম্যানিফেস্ট। হিস্ট্রি অংশের নিজস্ব ভার্সন আছে; শেলের অভ্যন্তরীণ fileHistory ব্যাকআপ অ্যাডাপ্টার দিয়ে সরবরাহ করা হয়। |
revision-history.json | ঐচ্ছিক, ম্যানুয়াল ব্যাকআপ | স্থায়ী creation ID, ধরে রাখা চেকপয়েন্ট, থাম্বনেইল এবং চলমান রিকভারি ড্রাফট। সমর্থিত হলে host.state.history.backup দিয়ে সরবরাহ করা হয়। |
file-history/versions/ | প্রতি স্ন্যাপশটে | আগের অ্যাসেট বাইট এবং এক্সট্র্যাক্ট করা ক্রেডেনশিয়াল, বর্তমান অ্যাসেটটি এখনও আছে কিনা তা নির্বিশেষে। |
file-history/results/ | প্রতি সম্পন্ন অপারেশনে | প্রকৃত আউটপুট বাইট। কনভার্শনের জন্য নির্বাচিত কোনো মূল ফাইল রাখা বা অন্তর্ভুক্ত করা হয় না। |
prefs.json | হ্যাঁ | ব্যবহারকারীর-মালিকানাধীন লোকাল পছন্দ: theme, sidebarWidth এবং ct-metrics কার্যকলাপ গণনা। |
lolly.txt | হ্যাঁ | Lolly ছাড়া zip খোলা যেকারো জন্য বান্ডেলের একটি মানুষ-পাঠযোগ্য সারসংক্ষেপ (গণনা, প্রোফাইল, ফাইলনাম)। প্রতিটি এক্সপোর্টে পুনরায় তৈরি হয় এবং ইমপোর্টে স্বীকৃত হয়, তাই এটি কখনো একটি বাদ পড়া অংশ হিসেবে গণ্য হয় না। এটি integrity ম্যাপের পরে লেখা হয়, তাই এটি তার বাইরে থাকে। |
বান্ডেলটি ইচ্ছাকৃতভাবে একটি সাধারণ zip: এটি যেকোনো পরিবহনে অক্ষত থাকে, এবং যেকোনো unzip টুল এটি পরিদর্শন করতে পারে।
profile.json সবচেয়ে ছোট অংশ এবং অ্যাপে রিডার প্রথমে যা দেখে: একজন প্রযোজক একবার যা পূরণ করেন তার বিবরণ, এবং টুলগুলোকে সেগুলো ব্যবহার করতে দেওয়ার অপ্ট-ইন।
signed by Lollyvector SVG১৫ paths~1.2k nodes৩০ groups১ image৪০ 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। এটি ছাড়া একটি ফাইল "not a Lolly backup" হিসেবে প্রত্যাখ্যাত হয়। |
formatVersion | এই বান্ডেলটি যে লেআউট দিয়ে লেখা হয়েছিল। অংশের সেট বা আকার পরিবর্তনে বৃদ্ধি পায়। রিডাররা এর উপর নির্ভর করে গেট করে না। |
minReader | এই বান্ডেলটি নিরাপদে ইমপোর্ট করার জন্য প্রয়োজনীয় সর্বনিম্ন রিডার ভার্সন। এই ফিল্ডের উপরই রিডাররা গেট করে। |
app | প্রস্তুতকারী অ্যাপ id, ডায়াগনস্টিকসের জন্য। |
exportedAt | বান্ডেলটি তৈরির ISO টাইমস্ট্যাম্প। |
counts | রাইটার যা যোগ করেছে, প্রদর্শন এবং sanity-checking-এর জন্য। |
integrity | ঐচ্ছিক। manifest.json ছাড়া প্রতিটি অংশকে তার আনকমপ্রেসড বাইটের একটি SRI-স্টাইল sha256-<base64> ডাইজেস্টের সাথে ম্যাপ করে। |
ভার্সন নীতি (forward compatibility)
formatVersion এবং minReader-এর মধ্যে এই বিভাজনটিই পুরনো ইনস্টলগুলোকে অনাথ না করে ফরম্যাটটিকে বাড়তে দেয়:
- একটি রিডার একটি বান্ডেল ইমপোর্ট করে যখন
manifest.minReader ≤তার নিজস্ব রিডার ভার্সন। এটি শুধুমাত্র প্রত্যাখ্যান করে ("needs a newer version of the app" সহ) যখন বান্ডেলটি স্পষ্টভাবে একটি নতুন রিডার দাবি করে। - একটি additive পরিবর্তন - একটি নতুন ঐচ্ছিক অংশ, বা একটি নতুন ঐচ্ছিক ম্যানিফেস্ট ফিল্ড -
formatVersionবাড়ায় কিন্তুminReaderঅপরিবর্তিত রাখে। পুরনো অ্যাপগুলো তখনও তাদের স্বীকৃত প্রতিটি অংশ ইমপোর্ট করে। তারা যেসব অংশ চেনে না, সেগুলো বাদ দেওয়া হয় (নিচে দেখুন), নীরবে ফেলে দেওয়া হয় না। - একটি breaking পরিবর্তন - যেখানে একটি অংশের ভুল ইমপোর্ট ডেটা নষ্ট করে, বা যেখানে পূর্বে ঐচ্ছিক একটি অংশ বাধ্যতামূলক হয়ে যায় -
minReaderবাড়ায়। পুরনো অ্যাপগুলো তখন এমন কিছু ইমপোর্ট করার পরিবর্তে পরিষ্কারভাবে প্রত্যাখ্যান করে যা তারা সামলাতে পারে না। - যদি একটি ভবিষ্যৎ বান্ডেল
formatVersionসেট করে কিন্তুminReaderবাদ দেয়, তাহলে রিডাররা সতর্কতার সাথেformatVersion-এর উপর গেট করার দিকে ফিরে যায় (পরিবর্তনটিকে breaking হিসেবে গণ্য করে)।
লেখকদের জন্য সাধারণ নিয়ম: যদি প্রতিটি বিদ্যমান রিডার আপনার সংযোজন উপেক্ষা করেও সঠিক কাজ করে, তাহলে এটি additive -
formatVersionবাড়ান,minReaderঅপরিবর্তিত রাখুন। অন্যথায়minReaderবাড়ান।
অখণ্ডতা
যখন manifest.integrity উপস্থিত থাকে, একটি রিডার কিছু লেখার আগে তালিকাভুক্ত প্রতিটি অংশের SHA-256 যাচাই করে। একটি অমিল ("failed its integrity check") বা একটি অনুপস্থিত অংশ ("incomplete") সম্পূর্ণ ইমপোর্ট বাতিল করে দেয় - কোনো আংশিক পুনরুদ্ধার নেই। এটি ফাইল পরিবহনে সৃষ্ট বিকৃতি ধরে ফেলে (একটি ছেঁটে যাওয়া AirDrop, একটি ইমেইল গেটওয়ে যা অ্যাটাচমেন্ট পুনরায়-এনকোড করেছে, একটি খারাপ USB সেক্টর)।
Integrity ইচ্ছাকৃতভাবে best-effort: এটি শুধুমাত্র সেখানে লেখা হয় যেখানে Web Crypto উপলব্ধ (প্রতিটি সিকিউর ব্রাউজার কনটেক্সট এবং আধুনিক Node), এবং শুধুমাত্র তখনই যাচাই করা হয় যখন ম্যাপ এবং Web Crypto উভয়ই উপস্থিত। ম্যাপ ছাড়া একটি বান্ডেল - উদাহরণস্বরূপ integrity চালু হওয়ার আগের একটি - অপরিবর্তিতভাবে ইমপোর্ট হয়। "Cannot verify"-কে কখনো "corrupt" হিসেবে গণ্য করা হয় না।
ম্যানিফেস্টটি নিজেকে বা পুনরায় তৈরি করা lolly.txt README-কে তালিকাভুক্ত করে না। ডাইজেস্টগুলো শুধু সেই অংশগুলো কভার করে যেগুলোর জন্য ম্যানিফেস্ট নিশ্চয়তা দেয়।
ইমপোর্ট সিমান্টিক্স
ইমপোর্ট একটি merge, কখনো replace-all নয়:
- টার্গেটের বিদ্যমান ডেটা যেমন আছে তেমনই থাকে।
- যখন কোনো সেশন স্লট বা আপলোড করা ইমেজ id দুটোতেই থাকে, তখন সাম্প্রতিক সময়ে সেভ করা কপিটি রাখা হয়, যাতে কোনো পুরনো ব্যাকআপ টার্গেটের নতুন কাজ কখনো প্রতিস্থাপন না করে। সমান বা অজানা সময় হলে টার্গেটের কপি রাখা হয়। creation history-সহ একটি ওয়েব ইনস্টলে, একই নিয়ম ঠিক করে একটি creation-এর কোন কপিটি বর্তমান থাকে, আর অন্য কপিটি একটি protected draft হিসেবে রাখা হয় (নিচে দেখুন)।
- প্রোফাইল রেকর্ড মার্জ করা হয়, প্রতিস্থাপিত নয়। টার্গেটের প্রতিটি ফোল্ডার তার বিষয়বস্তুসহ থেকে যায়; বান্ডেলের এমন ফোল্ডার যা টার্গেটের নেই তা যোগ করা হয়, আর দুটোতেই থাকা ফোল্ডার টার্গেটের নাম ও parent বজায় রাখে এবং বান্ডেলের যেসব সদস্য তার নেই তা পেয়ে যায়। টার্গেটের কোনো ফোল্ডারে ফাইল করা সেশন সেখানেই ফাইল থাকে।
- ফেভারিট (টুল, ক্যাটালগ অ্যাসেট ও Projects আইটেম) একত্র করা হয়। বান্ডেলের টেমপ্লেট, Projects টেমপ্লেট ও ইউজার টুল তখনই যোগ করা হয় যখন টার্গেটের কাছে সেই id-র কোনো রেকর্ড নেই। দুই দিকের Trash এন্ট্রি রাখা হয়, যাতে যে আইটেম যেকোনো ইনস্টলে পুনরুদ্ধারযোগ্য ছিল তা এখনও করা যায়।
- প্রোফাইলের বাকি প্রতিটি ফিল্ড (নাম, যোগাযোগের বিবরণ, ভাষা, ফিচার ফ্ল্যাগ, লুকানো টুল ও অন্যান্য সেটিংস) টার্গেটের মান বজায় রাখে। টার্গেটে খালি থাকা কোনো ফিল্ড বান্ডেলের মান নেয়।
prefs.json-এর ক্ষেত্রেও তাই: কোনো পছন্দ কেবল সেখানেই লেখা হয় যেখানে টার্গেটের কোনোটি নেই। - Device sync-এর সাধারণ প্রয়োগ এর ব্যতিক্রম: ডিভাইসগুলোকে সমান রাখতে গিয়ে, এটি synced কপির প্রোফাইল রেকর্ড, পছন্দ, সেশন ও ছবি নিয়ে নেয়। কোনো পুরনো কপি পুনরুদ্ধার করাও একই কাজ করে, কারণ এটি ইচ্ছাকৃতভাবে সময়ে পিছিয়ে যায়। প্রথম join, এটি এই ডিভাইসে আনুন, একটি ইমপোর্টের মতোই মার্জ করে।
- পুরনো অ্যাসেট ভার্সন এবং অপারেশন ID অপরিবর্তনীয় ব্যতিক্রম: পুনরায় ইমপোর্ট idempotent, এবং যে ID আগে থেকে ভিন্ন বাইট/হিস্ট্রির নাম বহন করে তা প্রতিস্থাপিত না হয়ে প্রত্যাখ্যাত হয়। একটি অভিন্ন বর্তমান অ্যাসেট পুনরায় ইমপোর্ট করলে তার ভার্সন অক্ষত থাকে। বদলে যাওয়া বর্তমান অ্যাসেটকে আলাদা ভার্সন বহন করতে হয়।
- Creation history-ও মার্জ হয়। কোনো creation দুই দিকেই থাকলে, সাম্প্রতিক সময়ে সেভ করা কপিটি বর্তমান হিসেবে এবং অন্য কপিটি একটি protected draft হিসেবে রাখে; যে creation-এর স্লট টার্গেট অন্য একটি creation-এর জন্য ব্যবহার করে, তা তার পাশে যোগ করা হয়; টার্গেটের Trash-এ থাকা creation সেখানেই থাকে। কোনো checkpoint id যা টার্গেটে ভিন্ন কনটেন্টের নাম বহন করে তা টার্গেটেরটি বজায় রাখে। কোনো আর্কাইভ যা নিজের চেক ব্যর্থ করে তা যেকোনো প্রোফাইল, সেশন, অ্যাসেট বা পছন্দ পরিবর্তনের আগেই ইমপোর্ট থামিয়ে দেয়। একটি অভিন্ন পুনরায় ইমপোর্ট কোনো স্টোরেজ যোগ করে না।
- বান্ডেলে না থাকা কিছুই স্পর্শ করা হয় না। টার্গেটে থাকা কিন্তু বান্ডেলে না থাকা একটি সেশন ইমপোর্টের পরেও টিকে থাকে।
সেভ করা সেশনগুলো স্বয়ংক্রিয়ভাবে তাদের ইমেজের সাথে পুনরায়-লিংক হয়: অ্যাসেট রেফারেন্সগুলো id দিয়ে রাখা হয়, এবং আপলোড করা ইমেজগুলো পুনরুদ্ধার হওয়ার পর bridge সেগুলো পুনরায়-রিজলভ করে (যেভাবেই হোক এটি করতেই হবে, কারণ blob: URL রিলোডে টিকে থাকে না)।
ইমপোর্ট সারসংক্ষেপ রিপোর্ট করে { profile, sessions, userAssets, prefs, skipped, failedAssets }। failedAssets সেইসব আপলোড করা অ্যাসেট গণনা করে যেগুলো পুনরুদ্ধার করা যায়নি (যেমন ডিভাইসের স্টোরেজ পূর্ণ)। এটি skipped-এর থেকে আলাদা, যা একটি forward-compatible নতুন রাইটারের সেই অংশগুলো গণনা করে যা এই বিল্ড চিনতে পারেনি। UI skipped-কে প্রকাশ করে ("… · N newer items skipped"), যাতে পুনরুদ্ধারটি কী রেখে গেছে সে বিষয়ে সৎ থাকে।
যখন file history উপস্থিত থাকে, সারসংক্ষেপ assetVersions, fileOperations এবং failedHistory-ও বহন করে। স্টোরেজ শেষ হয়ে যাওয়া বা অপরিবর্তনীয়-ID সংঘর্ষ আংশিক পুনরুদ্ধারের কারণ হতে পারে; UI ব্যবহারকারীকে সোর্স ব্যাকআপ ধরে রাখতে বলে। আংশিক বা অসমর্থিত পুনরুদ্ধারের পর Cloud sync তার প্রযুক্ত রিভিশন এগিয়ে নেয় না, তাই স্ন্যাপশটটি পুনরায় চেষ্টার জন্য উপলব্ধ থাকে। পুনরুদ্ধার সব প্রোফাইল/সেশন/অ্যাসেট/হিস্ট্রি স্টোরে একটিমাত্র transaction নয়।
Creation history (v3)
একটি history-সক্ষম ওয়েব হোস্ট থেকে ম্যানুয়াল ব্যাকআপে নিজস্ব { version: 1, documents, revisions, recoveries } স্কিমাসহ revision-history.json অন্তর্ভুক্ত থাকে। এটি ধরে রাখা ID, ক্যানোনিক্যাল ইনপুট স্ন্যাপশট, ভার্সন স্ট্যাম্প, রাস্টার প্রিভিউ এবং আলাদা রাইটার ড্রাফট বহন করে। হিস্ট্রি অ্যাডাপ্টার বর্তমান সেশন এবং তাদের head একটি রিড transaction-এ ক্যাপচার করে; sessions.json পুরনো রিডারের জন্য একই বর্তমান স্ন্যাপশট ব্যবহার করে।
পুনরুদ্ধার আর্কাইভটিকে একটি transaction-এ কমিট করার আগে payload SHA-256 এবং বাইট গণনা, ইউনিক পরিচয়, ডকুমেন্ট/head সম্পর্ক, বংশপরিচয়, টাইমস্ট্যাম্প, প্রিভিউ ধরন ও সীমা যাচাই করে। কম্প্যাক্ট করা parent রেফারেন্স অনুপস্থিত থাকতে পারে। বিদ্যমান বর্তমান কাজ কখনো নীরবে প্রতিস্থাপিত হয় না: কোনো creation দুই দিকেই থাকলে, যে দিকটি বর্তমান হিসেবে রাখা হয় না সেটি একটি protected draft হয়ে যায়। আর্কাইভের 384 MiB transfer সীমা স্পষ্টভাবে যাচাই করা হয়, এবং স্টোরেজ সীমা ধরে রাখা চেকপয়েন্ট না কেটেই প্রয়োগ করা হয়। সম্পূর্ণ ব্যাকআপ এখনও একটি ইন-মেমরি ZIP ইমপ্লিমেন্টেশন ব্যবহার করে এবং এটি কোনো স্ট্রিমিং আর্কাইভ নয়।
সারসংক্ষেপে revisions এবং recoveryDrafts যুক্ত হয়, যা শুধু গণনা করে এই ইমপোর্ট কী যোগ করেছে, আর added, kept, replaced, copies ও hidden জানায় প্রতিটি creation কীভাবে merge হয়েছে। এই সক্ষমতা ছাড়া একটি শেল সাধারণ সেশন পুনরুদ্ধার করে এবং history অংশটি skipped হিসেবে রিপোর্ট করে। নেটিভ ফাইলসিস্টেম history তখনই সমর্থিত হবে যখন এর অ্যাডাপ্টার টিকসই history transaction দেবে। P2P গেস্ট স্টেটে কোনো টিকসই history বা recovery আর্কাইভ নেই।
ব্যক্তিগত স্ন্যাপশট sync স্পষ্টভাবে creation history বাদ রাখে। history-ধারী একটি লোকাল ডকুমেন্টে স্ন্যাপশট প্রয়োগ করলে তার আগের কার্যরত অবস্থা একটি আলাদা recovery draft হিসেবে সংরক্ষিত থাকে এবং কোনো খোলা এডিটরের write token বাতিল হয়ে যায়। এর অপরিবর্তনীয় চেকপয়েন্ট ডিভাইসেই থেকে যায়। এটি স্ন্যাপশট প্রতিস্থাপনের সময় লোকাল history রক্ষা করে; এটি একইসাথে চলা ডিভাইস history মার্জ করে না।
পুরনো অ্যাসেট রেফারেন্স ধরে রাখা হয়, যদিও রেন্ডারিং এখনও গন্তব্যের বিদ্যমান লাইব্রেরির মাধ্যমে অ্যাসেট রিজলভ করে। এই আর্কাইভ এখনও প্রকৃত পুরনো অ্যাসেট বাইট বা পুরনো টুল রেন্ডারের নিশ্চয়তা দেয় না। অ্যাসেট-ভার্সন এবং file-result বাইট তাদের বিদ্যমান আলাদা ব্যাকআপ অংশের মাধ্যমে ভ্রমণ চালিয়ে যায়।
সেভ করা ভার্সন এবং ফাইল রিজাল্ট (v2)
ঐচ্ছিক history অংশে থাকে { version: 2, assetVersions: [...], operations: [...], batches: [...] }; রিডাররা batches ছাড়া আগের history-v1 আকৃতিও গ্রহণ করে। প্রতিটি স্ন্যাপশট স্থায়ী অ্যাসেট ID এবং প্রকৃত ভার্সন, তার সেভের সময়, বাইট দৈর্ঘ্য ও hex SHA-256 চিহ্নিত করে, সাথে একটি অ্যাসেট রেকর্ড যার _file এবং ঐচ্ছিক _credentialFile বাইনারি অংশের দিকে নির্দেশ করে। অপারেশন মূল ফাইল ফ্যাক্ট, রিকোয়েস্ট, রিপোর্ট, টাইমস্ট্যাম্প এবং ঐচ্ছিক রিজাল্ট _file বহন করে; স্টোরেজ ব্যাকএন্ড নাম, OPFS হ্যান্ডেল এবং execution lease ভ্রমণ করে না। পুরনো কেবল-history-v1 রিডার ইমপোর্টের আগে নতুন history ভার্সন প্রত্যাখ্যান করে, নীরবে batch সদস্যতা ফেলে দেওয়ার বদলে।
প্রসেসিংয়ের আগে ব্যাচ ম্যানিফেস্ট প্রতিটি নির্বাচিত সোর্স রেকর্ড করে, যার মধ্যে আছে কখনো না-পড়া ফাইল, বাতিল হওয়া সদস্য, রিজাল্ট স্পেস reserve করতে ব্যর্থতা এবং বাধাগ্রস্ত কাজ। প্রতিটি সদস্যের একটি স্থায়ী operation ID, সোর্স রেফারেন্স/ফ্যাক্ট, চাওয়া আউটপুট নাম এবং টার্মিনাল রিপোর্ট থাকে। একটি না-পড়া সোর্সের ঘোষিত ফ্যাক্ট থাকে, কোনো বানানো digest নয়। ইমপোর্ট সদস্যের পরিচয় এবং বহন করা কোনো অপারেশন রিপোর্টের সাথে সামঞ্জস্য যাচাই করে। ব্যাচ রিপোর্ট তখনও উপলব্ধ থাকে যখন পৃথক রিজাল্ট স্পষ্টভাবে সরানো হয়েছে, কিন্তু একটি রসিদ এই বোঝায় না যে তার আউটপুট বাইট এখনও সংরক্ষিত।
- প্রোফাইল বা অ্যাসেট ইমপোর্টের কোনো লেখার আগে প্রতিটি জ্ঞাত history রেকর্ড, রিপোর্ট এবং রেফারেন্স করা ফাইল যাচাই করা হয়। অনুপস্থিত বাইট এবং অমিল SHA-256 ব্যর্থ হয় এমনকি এনভেলপে কোনো integrity map না থাকলেও। এক্সট্র্যাক্ট করা ক্রেডেনশিয়াল বাইট অ্যারে থেকে যায়, এমনকি সেই পুরনো রাইটার থেকে ইমপোর্টেও যারা এগুলো numeric-key অবজেক্ট হিসেবে JSON-সিরিয়ালাইজ করেছিল।
- চলমান অপারেশন ব্যাকআপে বাধাগ্রস্ত রেকর্ড হয়ে যায়, একটি ব্যাখ্যামূলক ব্যর্থতা রিপোর্ট সহ এবং কোনো রিজাল্ট ছাড়াই। পুনরুদ্ধার কখনো ব্যাকগ্রাউন্ড কাজ পুনরায় শুরু করে না বা কোনো সক্রিয় lease ইমপোর্ট করে না। পুনরায় চেষ্টার জন্য মূল ফাইল বেছে নিতে হয়, উপলব্ধ থাকলে তার রেকর্ড করা SHA-256-এর বিরুদ্ধে যাচাই করা হয়।
- পুনরুদ্ধার করা রিজাল্ট তাদের বাইট ও মেটাডেটা একসাথে IndexedDB-এ কমিট করে। সাধারণ নতুন রিজাল্ট উপলব্ধ থাকলে OPFS ব্যবহার করে, IndexedDB fallback সহ। কোনো বিদ্যমান লাইভ অপারেশন কখনো কোনো ইমপোর্ট দ্বারা প্রতিস্থাপিত হয় না।
- history ZIP অ্যাসেম্বলি এখনও মেমরিতে হয়: বর্তমান সীমা 256 MiB history payload, 4 MiB history মেটাডেটা, সর্বোচ্চ 100 অপারেশন, 100 ব্যাচ এবং 2,000 স্ন্যাপশট। এক্সপোর্ট অতিরিক্ত বড় বা অসম্পূর্ণ history স্পষ্টভাবে প্রত্যাখ্যান করে; এটি কখনো নীরবে বাদ দেয় না। পুরনো লোকাল কপি সরানোর আগে গুরুত্বপূর্ণ ভার্সন/রিজাল্ট আলাদাভাবে ডাউনলোড করুন। এই সীমাগুলো ফোনের জন্য মাপা peak-memory নিশ্চয়তা নয়।
- লোকাল রিজাল্ট history-র বাজেট 512 MiB এবং 100-রেকর্ড ক্যাপ। অ্যাসেট স্ন্যাপশটের আলাদা 512 MiB বাজেট আছে এবং প্রতি অ্যাসেটে সর্বোচ্চ 20টি পুরনো ভার্সন; এক্সট্র্যাক্ট করা ক্রেডেনশিয়াল বাইট সেই স্ন্যাপশট বাজেটের মধ্যে গণনা হয়। পুনরুদ্ধার এই সীমাগুলো মেনে চলে এবং কখনো বিদ্যমান ব্যবহারকারীর ডেটা নীরবে সরিয়ে দেয় না।
- লোকাল ব্যাচ মেটাডেটার আলাদা 4 MiB বাজেট আছে, সর্বোচ্চ 100টি ম্যানিফেস্ট এবং প্রতি ব্যাচে 20 সদস্য। Pending সদস্যরা মেটাডেটা ক্যাপাসিটি reserve করে, প্রতি-সদস্য 32 KiB রিপোর্ট সীমাসহ। এটি একটি logical বাজেট, ব্রাউজার ডিস্ক-স্পেস নিশ্চয়তা নয়; একটি বাস্তব quota ব্যর্থতা প্রকাশ করা হয় এবং in-memory রিপোর্ট ডাউনলোডযোগ্য থাকে। একটি ব্যাচ সদস্যকে পুনরায় চেষ্টা করলে পুরনো রিপোর্ট ওভাররাইট না করেই একটি নতুন ব্যাচ তৈরি হয়। একটি ব্যাচ রেকর্ড সরালে পৃথক রিজাল্ট বাইট বা লাইব্রেরি অ্যাসেট সরে না।
- রূপান্তরিত রিজাল্ট normalization বা re-encoding ছাড়াই স্পষ্টভাবে লাইব্রেরিতে যোগ করা যায়। সোর্স/আউটপুট হ্যাশ এবং অপারেশন সম্পর্ক অ্যাসেটের সাথে থাকে। পুনরাবৃত্ত যোগ একটি অপরিবর্তিত কপি পুনর্ব্যবহার করে; একটি এডিট করা কপি কখনো ওভাররাইট হয় না। রাস্টার ইমেজ একটি নতুন Design ডকুমেন্ট শুরু করতে পারে। সেই ডকুমেন্ট বর্তমান লাইব্রেরি অ্যাসেট ID ব্যবহার করে: Design-এর রানটাইম ও URL পথ জুড়ে সঠিক ভার্সন পিন প্রয়োগ করা এখনও আলাদা কাজ। SVG/HTML/PDF/ZIP রিজাল্ট এই হ্যান্ডঅফ দ্বারা opaque ফাইল অ্যাসেট হিসেবে রাখা হয়, বিশ্বস্ত ইন্টারঅ্যাক্টিভ/ভেক্টর কনটেন্টে উন্নীত করা হয় না।
- Convert → Recent file operations history ব্যবহার, রিপোর্ট, ডাউনলোড এবং ভার্সন ম্যানেজার দেখায়। ম্যানেজার মুছে ফেলা লাইব্রেরি অ্যাসেটের পুরনো ভার্সনও খুঁজে পায়। একটি স্ন্যাপশট পুনরুদ্ধার করলে একটি নতুন বর্তমান ভার্সন তৈরি হয় যখন নির্বাচিত স্ন্যাপশটটি অক্ষত থাকে। সেটিংস → স্টোরেজ disposable ক্যাশ থেকে আলাদাভাবে রিজাল্ট ও ভার্সন হিসাব করে।
- স্পষ্ট temporary-file cleanup শুধু অপারেশন-মালিকানাধীন, রেফারেন্সহীন বাইট সরায়। বর্তমান রেকর্ড তাদের ফাইল রক্ষা করে; সাম্প্রতিক OPFS ফাইলের একটি এক ঘণ্টার গ্রেস পিরিয়ড আছে। সেভ করা রিজাল্ট এবং অ্যাসেট স্ন্যাপশট স্বয়ংক্রিয়ভাবে সাফ হয় না।
পুরনো রিডাররা এখনও v2 এনভেলপ (minReader: 1) গ্রহণ করে এবং পরিচিত অংশ পুনরুদ্ধার করে, অসমর্থিত history অংশকে skipped হিসেবে গণনা করে। সম্পূর্ণ history পুনরুদ্ধারের জন্য fileHistory অ্যাডাপ্টারসহ একটি শেল প্রয়োজন; এটি একটি শেল-অভ্যন্তরীণ সংযোগ, কোনো নতুন টুল-মুখী HostV1 সক্ষমতা নয়। বাস্তব দুই-ডিভাইস পুনরুদ্ধার লোকাল Chromium গেট দ্বারা কভার করা; ইনস্টল করা Tauri/iOS/Android পুনরুদ্ধারের গ্রহণযোগ্যতা আলাদা থেকে যায়।
কী ভ্রমণ করে না
- Catalog caches (ডাউনলোড করা অ্যাসেট মেটাডেটা ও ব্লব, টুল ইনডেক্স) - টার্গেটে বিনামূল্যে পুনরায়-সিঙ্ক হয়।
- Catalogue tools and catalogue assets - স্কোপের বাইরে, এবং ধরে নেওয়া হয় যে সেগুলো টার্গেটে ইতিমধ্যে উপস্থিত। ব্যবহারকারীর যোগ করা ব্র্যান্ড টোকেন, ফন্ট ও লোগো ইউজার অ্যাসেট, তাই সেগুলো ভ্রমণ করে।
blob:/ object URLs - লোডের সময় bridge দ্বারা পুনরায় তৈরি হয়।- Conversion originals, live execution lease এবং machine-local access/signing secret - পোর্টেবল history payload নয়। একটি সেভ করা রিজাল্ট একটি কপি, এই প্রতিশ্রুতি নয় যে মূল সোর্স ব্যাকআপ করা হয়েছিল।
- The export sequence counter - প্রতি-দিন ডাউনলোড-নামকরণ কাউন্টার (
localStoragekeylolly-export-seq) একটি লোকাল নামকরণ সুবিধা মাত্র। এটিPREF_KEYS-এর বাইরে রাখা হয়, তাই এটি কখনো একটি বান্ডেলে থাকে না।
স্টোরেজ মিটার একই বিভাজনটি আইটেমাইজ করে। Saved sessions, My images এবং File results ও versions একটি বান্ডেলে থাকে। তাদের নিচের asset cache, tool previews এবং offline pins সবই পুনরায়-উদ্ভূতযোগ্য, তাই সেগুলো পেছনে থেকে যায়।
signed by Lollyvector SVG৩৭ paths~4.9k nodes৮৫ groups৬৫ KBনিজেই যাচাই করুনস্বাক্ষরিত ফাইলটি নিন
signed by Lollyvector SVG৩৭ paths~4.9k nodes৮৫ groups৬৫ KBনিজেই যাচাই করুনস্বাক্ষরিত ফাইলটি নিন
ক্রস-শেল গ্যারান্টি
data-transfer.ts শুধুমাত্র ক্যাপাবিলিটি ব্রিজের (host.profile, host.state, host.assets) মাধ্যমে এবং শেয়ার্ড localStorage prefs-এর মাধ্যমে পড়ে ও লেখে। একই মডিউল ওয়েব ও Tauri-তে সাধারণ এনভেলপ পড়ে ও লেখে, IndexedDB বা ফাইল সিস্টেম স্টোরেজের উপরে। ঐচ্ছিক history অংশ শুধু তখনই দেখা যায় যখন সংশ্লিষ্ট অ্যাডাপ্টার উপলব্ধ; ইমপোর্টে একটি অসমর্থিত অংশ skipped হিসেবে রিপোর্ট করা হয়। হেডলেস স্যুট সাধারণ অংশগুলো একটি ইন-মেমরি ব্রিজের বিপরীতে চালায়, যেখানে history transaction-এর জন্য real-browser টেস্টও আছে।
দুটি শেল ভিন্ন কারণে এই গ্যারান্টির বাইরে থাকে:
- one-shot CLI-এর বহন করার মতো কিছু নেই - এর স্টেট প্রতিটি কল অনুযায়ী মেমরিতে এবং সাময়িক।
- TUI স্টেট ধরে রাখে (
~/.lolly: sessions, folders, profile) এবং এর Profile ভিউ এটি ব্যাকআপ করতে পারে, কিন্তু এটি নিজের একটি সরলতর আর্কাইভ লেখে: প্রতি সেশনেsaved-state/<slot>.jsonএবংprofile.jsonওfolders.json, কোনো ম্যানিফেস্ট,formatVersion/minReaderবা ইন্টিগ্রিটি ম্যাপ ছাড়াই। এটি এই ফরম্যাটে আমদানিযোগ্য নয় - একটি রিডার এটিকে "not a Lolly backup" বলে প্রত্যাখ্যান করে - এবং বিভ্রান্তিকরভাবে এটি একই ধরনের নাম ব্যবহার করে (lolly-backup-<stamp>.zip)। এই দুটিকে একীভূত করা একটি পরিচিত ফাঁক।
সংরক্ষিত এক্সটেনশন পয়েন্ট
এনভেলপটি ডিজাইন অনুযায়ী একটি ম্যানিফেস্ট এবং নামযুক্ত পার্টের একটি সেট, যাতে পরবর্তীতে নতুন ধরনের পোর্টেবল ডেটা এতে কোনো ব্রেকিং চেঞ্জ ছাড়াই যুক্ত হতে পারে। এগুলো অতিরিক্ত পার্ট হিসেবে যুক্ত হয় (নতুন formatVersion, একই minReader), এবং আজকের রিডার যা চেনে না তা এড়িয়ে যায়। এগুলো এখনও বানানো হয়নি। নামগুলো এখানে সংরক্ষিত রাখা হয়েছে যাতে এগুলো চালু হলে ফরম্যাটটি সংগতিপূর্ণ থাকে।
tokens.json- design tokens. একটি W3C DTCG ডিজাইন-টোকেন ডকুমেন্ট (যে ফরম্যাট Penpot ইমপোর্ট ও এক্সপোর্ট করে -$value/$type/$descriptionসহ টোকেন, গ্রুপ, সেট ও থিমে সংগঠিত)। বান্ডেলে একটি টোকেন সেট থাকলে ব্যবহারকারী তার সেশনের পাশাপাশি ব্র্যান্ড প্রিমিটিভও ইনস্টলের মধ্যে সরাতে পারেন। (ব্যবহারকারীর নিজের ব্র্যান্ড টোকেন আজওassets.json-এuser/tokens/brandঅ্যাসেট হিসেবে ভ্রমণ করে; এই অংশ তার সেট ও থিমসহ একটি সম্পূর্ণ DTCG ডকুমেন্ট বহন করবে।) দীর্ঘমেয়াদে, ইনজেস্ট করা টোকেন সেট একটি প্রথম-শ্রেণীর উৎস হয়ে উঠবে যার বিপরীতে টুল ও প্যালেট অ্যাসেট রিজলভ করবে।penpot/- ingested Penpot files. একটি Penpot ফাইল (অথবা তার এক্সট্র্যাক্ট করা, Lolly-প্রাসঙ্গিক সাবসেট) একটি টুল হিসেবে ইমপোর্ট ও প্রদর্শনের জন্য একটি সংরক্ষিত ডিরেক্টরি। বান্ডেলটি ইনজেস্ট করা ডেফিনিশন বহন করবে, যাতে এটি ব্যবহারকারীর বাকি ডেটার সাথে ভ্রমণ করে।
এই সংরক্ষিত নাম এবং উপরের পার্টগুলোর বাইরের যেকোনো কিছু একটি রিডারের কাছে অজানা পার্ট: অপরিবর্তিত রেখে দেওয়া হয় এবং skipped-এ গণনা করা হয়।
রেফারেন্স
- মডিউল:
shells/web/src/data-transfer.ts(exportBackup,importBackup,BACKUP_FORMAT,BACKUP_FORMAT_VERSION,BACKUP_READER_VERSION-backupFilename()নেমার অভ্যন্তরীণ)। - কন্ট্র্যাক্ট টেস্ট:
tests/data-transfer.test.ts- রাউন্ড-ট্রিপ, মার্জ, ইন্টিগ্রিটি, ফরওয়ার্ড-কম্প্যাট এবং রিডার-গেট কেস। - History কন্ট্র্যাক্ট টেস্ট:
tests/file-history-backup.test.ts,tests/file-batch-history.test.tsএবংtests/file-result-library.test.ts। ব্রাউজার acceptance:tests/file-history.browser.test.ts,tests/file-batch-history.browser.test.tsএবংtests/file-result-reuse.browser.test.ts। - ব্যবহৃত ব্রিজ সারফেস:
host.profile,host.state,host.assets- দেখুন Host API।