كل ما يجمعه مستخدم Lolly يعيش على جهازه - بلا حساب، بلا سحابة. حزمة نقل البيانات هي وسيلة انتقال تلك القيمة: صدّرها من تثبيت واحد، واحمل الملف بأي وسيلة (USB، AirDrop، بريد إلكتروني لنفسك، مشاركة شبكية) واستورده في تثبيت آخر. الملف هو وسيلة النقل. يمكن أن تكون الوجهة غير متصلة أو متصلة بالإنترنت. لا فرق، لأن لا شيء يتواصل مع خادم على الإطلاق.
signed by Lollyvector SVGتحقق بنفسكGet the signed file12 paths~5.1k nodes12 groups60 KB
signed by Lollyvector SVGتحقق بنفسكGet the signed file12 paths~5.1k nodes12 groups60 KB
هذه الصفحة هي مواصفة التنسيق. لدليل المستخدم النهائي راجع Using Lolly → الانتقال إلى جهاز آخر. التنفيذ موجود في shells/web/src/data-transfer.ts، ويثبّت tests/data-transfer.test.ts عقد الذهاب والإياب.
النطاق. تحمل الحزمة بيانات المستخدم، لا الأدوات. تُزامن الأدوات وأصول الكتالوج بشكل منفصل، ويُفترض أنها موجودة بالفعل على الجهاز الهدف (في أسوأ الحالات بإصدار أحدث). لا يقوم الاستيراد أبدا بتثبيت أداة أو ترقيتها.
الأهداف
- تنسيق واحد، لكل قشرة (shell). تُنتَج البايتات نفسها وتُستهلك من قِبل الـ PWA على الويب، وتطبيقات Tauri لسطح المكتب/الجوال، وأي قشرة مستقبلية. الحزمة هي العقد. جسر القدرات الخاص بكل قشرة هو المحوّل الخاص بالمنصة خلفه.
- تنجو من الرحلة. حزمة تالفة أو مبتورة أثناء النقل تفشل بصوت عالٍ عند الاستيراد، ولا تستعيد جزئيا أبدا.
- تعيش أطول من هذا الإصدار. لا يزال بإمكان تطبيق أقدم استيراد الأجزاء المعروفة لديه من حزمة أحدث. أما التنسيق الذي يُحدث كسرا حقيقيا فيُرفض بشكل نظيف.
- آمن للدمج. استيراد حزمة إلى تثبيت قيد الاستخدام بالفعل لا يمحو أبدا أي شيء لم يكن في الحزمة.
المغلّف
الحزمة ملف .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 | نعم | معرّف التنسيق، والإصدارات، والأعداد، وسلامة كل جزء. أول شيء ينظر إليه القارئ. |
profile.json | عند ضبطه | سجل me الخاص بالمستخدم (الاسم، جهة الاتصال، مرجع الصورة الشخصية، الأعلام). يُقرأ عبر host.profile. |
sessions.json | نعم | كل جلسة محفوظة: الفتحة، معرّف/إصدار الأداة، التسمية، الصورة المصغّرة (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 هو أصغر جزء والجزء الذي يراه القارئ أولا في التطبيق: التفاصيل التي يملؤها المُنشئ مرة واحدة، بالإضافة إلى الموافقة التي تسمح للأدوات باستخدامها.
signed by Lollyvector SVGتحقق بنفسكGet the signed file18 paths~2.0k nodes41 groups30 KB
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 | الحد الأدنى لإصدار القارئ اللازم لاستيراد هذه الحزمة بأمان. هذا هو الحقل الذي يستند إليه القارئ في القرار. |
app | معرّف التطبيق المُنتِج، للتشخيص. |
exportedAt | الطابع الزمني ISO الذي أُنشئت فيه الحزمة. |
counts | ما وضعه الكاتب، للعرض والتحقق من السلامة. |
integrity | اختياري. يربط كل جزء عدا manifest.json بملخّص (digest) بنمط SRI sha256-<base64> لبايتاته غير المضغوطة. |
سياسة الإصدارات (التوافق المستقبلي)
الفصل بين formatVersion وminReader هو ما يسمح للتنسيق بالنمو دون التخلي عن التثبيتات الأقدم:
- يستورد القارئ حزمة عندما يكون
manifest.minReader ≤إصدار القارئ نفسه. يرفض (برسالة "needs a newer version of the app") فقط عندما تطلب الحزمة صراحة قارئا أحدث. - التغيير الإضافي - جزء اختياري جديد، أو حقل بيان اختياري جديد - يرفع
formatVersionلكنه يتركminReaderدون تغيير. لا تزال التطبيقات الأقدم تستورد كل جزء تتعرف عليه. تُتخطى الأجزاء التي لا تتعرف عليها (انظر أدناه)، ولا تُسقَط بصمت. - التغيير الكاسر - تغيير يؤدي فيه استيراد خاطئ لجزء إلى إتلاف البيانات، أو يصبح فيه جزء كان اختياريا إلزاميا - يرفع
minReader. حينها ترفض التطبيقات الأقدم بشكل نظيف بدلا من استيراد شيء لا يمكنها التعامل معه. - إذا ضبطت حزمة مستقبلية
formatVersionلكنها أغفلتminReader، يعود القرّاء بحذر إلى الاستناد إلىformatVersion(يعاملون التغيير كأنه كاسر).
قاعدة عملية للمؤلفين: إذا كان كل قارئ موجود سيتصرف بشكل صحيح رغم تجاهل إضافتك، فهي إضافية - ارفع
formatVersionواتركminReader. وإلا فارفعminReader.
السلامة
عندما يكون manifest.integrity موجودا، يتحقق القارئ من SHA-256 لكل جزء مُدرج قبل كتابة أي شيء. عدم التطابق ("failed its integrity check") أو غياب جزء ("incomplete") يُلغي الاستيراد بأكمله - لا استعادة جزئية. يلتقط هذا التلف الذي قد تُحدثه وسيلة نقل الملف (عملية AirDrop مبتورة، بوابة بريد إلكتروني أعادت ترميز المرفق، قطاع USB تالف).
السلامة مبذولة على أساس أفضل جهد بالتصميم: تُكتب فقط حيث تتوفر Web Crypto (كل سياق متصفح آمن وكل Node حديث)، وتُتحقَّق منها فقط عندما تتوفر الخريطة وWeb Crypto معا. تُستورَد الحزمة الخالية من الخريطة - مثلا حزمة من قبل وجود السلامة - دون تغيير. "لا يمكن التحقق" لا تُعامَل أبدا كـ"تالفة".
لا يُدرج البيان نفسه ولا ملف lolly.txt التمهيدي المُعاد توليده. تغطي الملخصات (digests) الأجزاء التي يكفلها البيان.
دلالات الاستيراد
الاستيراد هو دمج مع الاستبدال، وليس استبدالا كليا أبدا:
- تُترك البيانات الموجودة على الجهاز الهدف كما هي.
- أي مفتاح يتصادم - الملف الشخصي، فتحة جلسة، معرّف صورة مرفوعة - يُستبدل بالنسخة المستوردة.
- لا يُمس أي شيء لم يكن في الحزمة. الجلسة التي كانت موجودة على الجهاز الهدف ولم تكن في الحزمة تنجو من الاستيراد.
تُعيد الجلسات المحفوظة الربط بصورها تلقائيا: تُحفظ إشارات الأصول بالمعرّف، ويُعيد الجسر تحليلها بعد استعادة الصور المرفوعة (وهو مضطر لذلك على أي حال، لأن روابط blob: لا تنجو من إعادة التحميل).
يُبلّغ ملخص الاستيراد عن { profile, sessions, userAssets, prefs, skipped, failedAssets }. يحسب failedAssets الأصول المرفوعة التي تعذّرت استعادتها (امتلاء تخزين الجهاز، مثلا). وهو متمايز عن skipped، الذي يحسب الأجزاء من كاتب أحدث متوافق مستقبليا لم يتعرف عليها هذا الإصدار. تُظهر الواجهة skipped ("… · N newer items skipped")، بحيث تكون الاستعادة صادقة بشأن ما تركته وراءها.
ما لا ينتقل
- ذاكرات الكتالوج المؤقتة (بيانات وصفية وبايتات الأصول المنزّلة، فهرس الأدوات) - تُعاد مزامنتها مجانا على الجهاز الهدف.
- الأدوات وأصول العلامة - خارج النطاق، ويُفترض أنها موجودة بالفعل على الجهاز الهدف.
- روابط
blob:/ روابط الكائنات - تُعاد توليدها بواسطة الجسر عند التحميل. - عدّاد تسلسل التصدير - عدّاد تسمية التنزيل اليومي (مفتاح
localStorageباسمlolly-export-seq) هو راحة تسمية محلية. يُبقى خارجPREF_KEYS، لذا لا ينتقل أبدا داخل حزمة.
يفصّل مقياس التخزين الانقسام نفسه. تنتقل الجلسات المحفوظة وMy images داخل الحزمة. أما ذاكرة الأصول المؤقتة ومعاينات الأدوات والتثبيتات غير المتصلة أسفلها فكلها قابلة لإعادة الاشتقاق، لذا تبقى خلفا.
signed by Lollyvector SVGتحقق بنفسكGet the signed file25 paths~4.8k nodes46 groups59 KB
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. يختبر الاختبار غير المرئي (headless) الدورة الكاملة ذهابا وإيابا مقابل جسر في الذاكرة، ولهذا فهو يمثل جميعها.
يقع غلافان خارج هذا الضمان، لأسباب مختلفة:
- CLI أحادية التشغيل ليس لديها ما تحمله - حالتها في الذاكرة ومؤقتة لكل استدعاء.
- تحافظ TUI فعليا على الحالة (
~/.lolly: الجلسات، المجلدات، الملف الشخصي) ويمكن لعرض الملف الشخصي فيها إنشاء نسخة احتياطية منها، لكنها تكتب أرشيفا أبسط خاصا بها:sessions/<slot>.jsonلكل جلسة إضافة إلىprofile.jsonوfolders.json، بلا بيان (manifest)، وبلاformatVersion/minReaderوبلا خريطة سلامة. لا يمكن استيرادها بهذا التنسيق - يرفضها القارئ باعتبارها "ليست نسخة احتياطية من Lolly" - ومما يزيد الالتباس أنها تستخدم اسما مشابها (lolly-backup-<stamp>.zip). توحيد الاثنين فجوة معروفة.
نقاط امتداد محجوزة
المغلف عبارة عن بيان إضافة إلى مجموعة من الأجزاء المسماة بالتصميم، بحيث يمكن لأنواع جديدة من البيانات القابلة للنقل أن تُحمل عليه لاحقا دون تغيير جذري (breaking change). تُدرج كأجزاء إضافية (formatVersion جديد، ونفس minReader)، ويتجاهل القارئ الحالي ما لا يتعرف عليه. هذه الأجزاء مدرجة في خارطة الطريق، ولم تُنفذ بعد. الأسماء محجوزة هنا حتى يبقى التنسيق متسقا عند إضافتها.
tokens.json- رموز التصميم (design tokens). مستند رموز تصميم بمعيار W3C DTCG (التنسيق الذي يستورده ويصدره Penpot - رموز بحقول$value/$type/$description، منظمة في مجموعات (groups)، أطقم (sets) وسمات (themes)). تتيح مجموعة رموز داخل الحزمة للمستخدم نقل عناصر علامته التجارية الأساسية بين عمليات التثبيت جنبا إلى جنب مع جلساته. على المدى الأبعد، تصبح مجموعة الرموز المستوردة مصدرا أساسيا تحتكم إليه الأدوات وأصول لوحة الألوان.penpot/- ملفات Penpot المستوردة. دليل محجوز لملف 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- حالات الدورة الكاملة، الدمج، السلامة، التوافق التقدمي وبوابة القارئ. - سطح الجسر المستخدم:
host.profile،host.state،host.assets- انظر واجهة برمجة المضيف.