Data Transfer - lolly-backup বান্ডেল

একজন Lolly ব্যবহারকারী যা কিছু সঞ্চয় করেন তা তাদের ডিভাইসেই থাকে - কোনো অ্যাকাউন্ট নেই, কোনো ক্লাউড নেই। data-transfer বান্ডেল হলো সেই মূল্য স্থানান্তরের উপায়: এটি একটি ইনস্টলে এক্সপোর্ট করুন, যেকোনো মাধ্যমে ফাইলটি বহন করুন (USB, AirDrop, ইমেইল-টু-সেলফ, একটি নেটওয়ার্ক শেয়ার) এবং অন্যটিতে ইমপোর্ট করুন। ফাইলটিই পরিবহন। টার্গেট অফলাইন বা অনলাইন হতে পারে। এতে কোনো পার্থক্য হয় না, কারণ কখনো কোনো সার্ভারের সাথে যোগাযোগ হয় না।

পুরো একটি ইনস্টল সরিয়ে নেওয়ার দুটি বোতাম: Export my data একটি zip লেখে, Import data সেটি আবার পড়েsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file১২ paths~5.1k nodes১২ groups৬০ KBপুরো একটি ইনস্টল সরিয়ে নেওয়ার দুটি বোতাম: Export my data একটি zip লেখে, Import data সেটি আবার পড়েsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file১২ paths~5.1k nodes১২ groups৬০ KB

এই পৃষ্ঠাটি ফরম্যাট স্পেক। এন্ড-ইউজার ওয়াকথ্রুর জন্য দেখুন Using Lolly → Moving to another device। ইমপ্লিমেন্টেশনটি হলো shells/web/src/data-transfer.ts, এবং tests/data-transfer.test.ts round-trip কন্ট্র্যাক্টকে পিন করে।

Scope. একটি বান্ডেল ব্যবহারকারীর ডেটা বহন করে, টুল নয়। টুল এবং ক্যাটালগ অ্যাসেট আলাদাভাবে সিঙ্ক করা হয় এবং ধরে নেওয়া হয় যে সেগুলো টার্গেটে ইতিমধ্যে উপস্থিত (সবচেয়ে খারাপ ক্ষেত্রে উচ্চতর ভার্সনে)। ইমপোর্ট করা কখনো কোনো টুল ইনস্টল বা আপগ্রেড করে না।

লক্ষ্য

এনভেলপ

একটি বান্ডেল একটি সাধারণ .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 রেকর্ড (নাম, যোগাযোগ, হেডশট রেফ, ফ্ল্যাগ)। 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 খোলা যেকারো জন্য বান্ডেলের একটি মানুষ-পাঠযোগ্য সারসংক্ষেপ (গণনা, প্রোফাইল, ফাইলনাম)। প্রতিটি এক্সপোর্টে পুনরায় তৈরি হয় এবং ইমপোর্টে স্বীকৃত হয়, তাই এটি কখনো একটি বাদ পড়া অংশ হিসেবে গণ্য হয় না। এটি integrity ম্যাপের পরে লেখা হয়, তাই এটি তার বাইরে থাকে।

বান্ডেলটি ইচ্ছাকৃতভাবে একটি সাধারণ zip: এটি যেকোনো পরিবহনে অক্ষত থাকে, এবং যেকোনো unzip টুল এটি পরিদর্শন করতে পারে।

profile.json সবচেয়ে ছোট অংশ এবং অ্যাপে রিডার প্রথমে যা দেখে: একজন প্রযোজক একবার যা পূরণ করেন তার বিবরণ, এবং টুলগুলোকে সেগুলো ব্যবহার করতে দেওয়ার অপ্ট-ইন।

Profile details ফর্ম যা profile.json হয়ে ওঠে - নাম, যোগাযোগ, হেডশট এবং তাদের পাশে অপ্ট-ইনsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file১৮ paths~2.0k nodes৪১ groups৩০ KBProfile details ফর্ম যা profile.json হয়ে ওঠে - নাম, যোগাযোগ, হেডশট এবং তাদের পাশে অপ্ট-ইনsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file১৮ paths~2.0k nodes৪১ groups৩০ 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রাইটার যা যোগ করেছে, প্রদর্শন এবং sanity-checking-এর জন্য।
integrityঐচ্ছিক। manifest.json ছাড়া প্রতিটি অংশকে তার আনকমপ্রেসড বাইটের একটি SRI-স্টাইল sha256-<base64> ডাইজেস্টের সাথে ম্যাপ করে।

ভার্সন নীতি (forward compatibility)

formatVersion এবং minReader-এর মধ্যে এই বিভাজনটিই পুরনো ইনস্টলগুলোকে অনাথ না করে ফরম্যাটটিকে বাড়তে দেয়:

লেখকদের জন্য সাধারণ নিয়ম: যদি প্রতিটি বিদ্যমান রিডার আপনার সংযোজন উপেক্ষা করেও সঠিক কাজ করে, তাহলে এটি 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-overwrite, কখনো replace-all নয়:

সেভ করা সেশনগুলো স্বয়ংক্রিয়ভাবে তাদের ইমেজের সাথে পুনরায়-লিংক হয়: অ্যাসেট রেফারেন্সগুলো id দিয়ে রাখা হয়, এবং আপলোড করা ইমেজগুলো পুনরুদ্ধার হওয়ার পর bridge সেগুলো পুনরায়-রিজলভ করে (যেভাবেই হোক এটি করতেই হবে, কারণ blob: URL রিলোডে টিকে থাকে না)।

ইমপোর্ট সারসংক্ষেপ রিপোর্ট করে { profile, sessions, userAssets, prefs, skipped, failedAssets }failedAssets সেইসব আপলোড করা অ্যাসেট গণনা করে যেগুলো পুনরুদ্ধার করা যায়নি (যেমন ডিভাইসের স্টোরেজ পূর্ণ)। এটি skipped-এর থেকে আলাদা, যা একটি forward-compatible নতুন রাইটারের সেই অংশগুলো গণনা করে যা এই বিল্ড চিনতে পারেনি। UI skipped-কে প্রকাশ করে ("… · N newer items skipped"), যাতে পুনরুদ্ধারটি কী রেখে গেছে সে বিষয়ে সৎ থাকে।

কী ভ্রমণ করে না

স্টোরেজ মিটার একই বিভাজনটি আইটেমাইজ করে। Saved sessions এবং My images একটি বান্ডেলে থাকে। তাদের নিচের asset cache, tool previews এবং offline pins সবই পুনরায়-উদ্ভূতযোগ্য, তাই সেগুলো পেছনে থেকে যায়।

স্টোরেজ মিটার এই ডিভাইসের ডেটাকে নামযুক্ত ক্যাটাগরিতে ভাগ করছে, যেখানে Saved sessions এবং My images আলাদাভাবে Asset cache থেকে ট্র্যাক করা হয়, এখানে একটি নতুন ইনস্টলে যেখানে প্রতিটি ক্যাটাগরি এখনও খালিsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file২৫ paths~4.8k nodes৪৬ groups৫৯ KBস্টোরেজ মিটার এই ডিভাইসের ডেটাকে নামযুক্ত ক্যাটাগরিতে ভাগ করছে, যেখানে Saved sessions এবং My images আলাদাভাবে Asset cache থেকে ট্র্যাক করা হয়, এখানে একটি নতুন ইনস্টলে যেখানে প্রতিটি ক্যাটাগরি এখনও খালিsigned by Lollyvector SVGনিজেই যাচাই করুনGet the signed file২৫ paths~4.8k nodes৪৬ groups৫৯ KB

ক্রস-শেল গ্যারান্টি

data-transfer.ts শুধুমাত্র ক্যাপাবিলিটি ব্রিজের (host.profile, host.state, host.assets) মাধ্যমে এবং শেয়ার্ড localStorage prefs-এর মাধ্যমে পড়ে ও লেখে। যেহেতু ব্রিজই একমাত্র সংযোগস্থল, তাই একই মডিউল প্রতিটি শেলে বাইট-হুবহু বান্ডেল তৈরি করে, যদিও নিচের স্টোরেজ ভিন্ন - ওয়েবে IndexedDB, Tauri-তে ফাইল সিস্টেম। Tauri শেলগুলো এই মডিউল অপরিবর্তিতভাবে পুনরায় ব্যবহার করে। শুধু তাদের host.state বাস্তবায়ন ভিন্ন। হেডলেস টেস্টটি একটি ইন-মেমরি ব্রিজের বিপরীতে সম্পূর্ণ রাউন্ড-ট্রিপ যাচাই করে, তাই এটি এদের সবার প্রতিনিধিত্ব করে।

দুটি শেল ভিন্ন কারণে এই গ্যারান্টির বাইরে থাকে:

সংরক্ষিত এক্সটেনশন পয়েন্ট

এনভেলপটি ডিজাইন অনুযায়ী একটি ম্যানিফেস্ট এবং নামযুক্ত পার্টের একটি সেট, যাতে পরবর্তীতে নতুন ধরনের পোর্টেবল ডেটা এতে কোনো ব্রেকিং চেঞ্জ ছাড়াই যুক্ত হতে পারে। এগুলো অতিরিক্ত পার্ট হিসেবে যুক্ত হয় (নতুন formatVersion, একই minReader), এবং আজকের রিডার যা চেনে না তা এড়িয়ে যায়। এগুলো রোডম্যাপে আছে, এখনও বাস্তবায়িত হয়নি। নামগুলো এখানে সংরক্ষিত রাখা হয়েছে যাতে এগুলো চালু হলে ফরম্যাটটি সংগতিপূর্ণ থাকে।

এই সংরক্ষিত নাম এবং উপরের পার্টগুলোর বাইরের যেকোনো কিছু একটি রিডারের কাছে অজানা পার্ট: অপরিবর্তিত রেখে দেওয়া হয় এবং skipped-এ গণনা করা হয়।

রেফারেন্স