Lolly
Mở ứng dụng

Chuyển dữ liệu - gói lolly-backup

Mọi thứ mà một người dùng Lolly tích lũy đều nằm trên thiết bị của họ - không tài khoản, không đám mây. Gói chuyển dữ liệu là cách giá trị đó di chuyển: xuất nó trên một bản cài đặt, mang file đi bằng bất kỳ phương tiện nào (USB, AirDrop, gửi email cho chính mình, chia sẻ mạng) rồi nhập nó vào một bản cài đặt khác. File chính là phương tiện vận chuyển. Đích đến có thể offline hoặc online. Điều đó không quan trọng, vì không có gì từng liên lạc với máy chủ.

Hai nút di chuyển toàn bộ bản cài đặt: Export my data ghi ra một tệp zip, Import data đọc lại tệp đó signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBTự kiểm chứngTải tệp đã kýHai nút di chuyển toàn bộ bản cài đặt: Export my data ghi ra một tệp zip, Import data đọc lại tệp đó signed by Lollyvector SVG9 paths~4.9k nodes11 groups56 KBTự kiểm chứngTải tệp đã ký

Trang này là đặc tả định dạng. Để xem hướng dẫn dành cho người dùng cuối, xem Tìm và khôi phục công việc của bạn → Chuyển công việc của bạn sang thiết bị khác. Việc triển khai nằm ở shells/web/src/data-transfer.ts, và tests/data-transfer.test.ts chốt hợp đồng khứ hồi.

Phạm vi. Một gói mang dữ liệu người dùng, không phải công cụ danh mục. Công cụ danh mục và tài sản danh mục được đồng bộ riêng và được giả định là đã có sẵn trên máy đích (trường hợp xấu nhất là ở phiên bản cao hơn); các công cụ người dùng tự tạo di chuyển bên trong profile.json. Việc nhập không bao giờ cài đặt hay nâng cấp một công cụ danh mục.

Mục tiêu

Phong bì

Một gói chỉ là một .zip thông thường. File tải xuống được đặt tên theo người sở hữu nó - LollyTools-<First>-<Last>-<YYYY-MM-DD>-<n>.zip (ví dụ LollyTools-Ada-Lovelace-2026-06-26-1.zip) - để một thư mục Downloads chứa các bản sao lưu vẫn dễ đọc. Phần tên và họ lấy từ hồ sơ và bị bỏ qua khi chưa thiết lập. Không có hồ sơ sẽ cho LollyTools-2026-06-26-1.zip, và chỉ có tên riêng sẽ cho LollyTools-Ada-2026-06-26-1.zip. Mỗi phần được làm sạch thành một token an toàn cho tên file (giữ lại chữ cái/chữ số Unicode, loại bỏ khoảng trắng/dấu câu, giới hạn 32 ký tự). <n> là một chuỗi số theo từng ngày, từng thiết bị, để các lần xuất lặp lại trong cùng một ngày không trùng nhau và vẫn theo thứ tự. backupFilename() trong shells/web/src/data-transfer.ts xây dựng tên này. Nội dung của zip giống hệt nhau bất kể tên gọi. Bên trong:

Đường dẫnBắt buộcNội dung
manifest.jsoncóId định dạng, các phiên bản, số lượng và tính toàn vẹn theo từng phần. Điều đầu tiên trình đọc xem xét.
profile.jsonkhi đã thiết lậpToàn bộ bản ghi me của người dùng: tên, liên hệ, tham chiếu ảnh đại diện và cờ, cùng các thư mục, Thùng rác, bản thiết kế dự án, mẫu người dùng và các công cụ do người dùng tạo, mục yêu thích, công cụ đã ẩn, ngôn ngữ và lựa chọn emoji. Đọc qua host.profile.
sessions.jsoncóMọi phiên đã lưu: slot, id/phiên bản công cụ, nhãn, ảnh thu nhỏ (data-URL) và toàn bộ dữ liệu đầu vào. Đọc qua host.state.
assets.jsoncóSiêu dữ liệu cho mỗi tài sản đã tải lên (hình ảnh, font, token thương hiệu, logo, bản sao các tệp đã tải xuống), mỗi cái trỏ tới các byte của nó dưới assets/blobs/.
assets/blobs/<n>.<ext>theo từng tài sảnCác byte thô của tài sản (file hình ảnh và font). Được lưu không nén (các định dạng đã nén sẵn). Phần mở rộng chỉ mang tính hình thức. MIME trong assets.json mới là căn cứ chính thức.
assets/blobs/<n>.c2pakhi cóContent Credentials đã trích xuất dưới dạng byte nhị phân chính xác, được tham chiếu bởi _credentialFile trong bản ghi tài sản. Đây không phải là khóa ký của thiết bị.
design-systems.jsonkhi cóCác hệ thống thiết kế được tạo hoặc thêm vào trên bản cài đặt này, dưới dạng { active, records }. Được hợp nhất theo id khi nhập; lựa chọn active của gói chỉ áp dụng khi máy đích chưa có hệ thống thiết kế riêng.
file-history.jsontùy chọnCác bản chụp tài sản theo phiên bản, báo cáo thao tác tệp cuối cùng và các bản kê khai batch hoàn chỉnh. Phần lịch sử có phiên bản riêng; do bộ chuyển đổi sao lưu fileHistory nội bộ của shell cung cấp.
revision-history.jsontùy chọn, sao lưu thủ côngCác ID tạo tác ổn định, các checkpoint được giữ lại, ảnh thu nhỏ và các bản nháp phục hồi luân phiên. Do host.state.history.backup cung cấp khi được hỗ trợ.
file-history/versions/theo từng bản chụpByte tài sản trước đó và các credentials đã trích xuất, không phụ thuộc vào việc tài sản hiện tại có còn tồn tại hay không.
file-history/results/theo từng thao tác hoàn tấtByte đầu ra chính xác. Không giữ lại hay bao gồm tệp gốc đã chọn để chuyển đổi.
prefs.jsoncóTùy chọn cục bộ thuộc sở hữu người dùng: theme, sidebarWidth và số liệu hoạt động ct-metrics.
lolly.txtcóMột bản tóm tắt gói dễ đọc với con người (số lượng, hồ sơ, tên file) dành cho bất kỳ ai mở zip mà không có Lolly. Được tạo lại ở mỗi lần xuất và được nhận diện khi nhập, nên nó không bao giờ tính là một phần bị bỏ qua. Nó được ghi sau bản đồ toàn vẹn, nên nằm ngoài bản đồ đó.

Gói này cố tình chỉ là một zip thông thường: nó sống sót nguyên vẹn qua bất kỳ phương thức vận chuyển nào, và bất kỳ công cụ giải nén nào cũng có thể kiểm tra nó.

profile.json là phần nhỏ nhất và là phần mà trình đọc thấy đầu tiên trong ứng dụng: các thông tin mà người tạo điền một lần, cộng với tùy chọn cho phép các công cụ sử dụng chúng.

Biểu mẫu chi tiết Hồ sơ trở thành profile.json: tên, thông tin liên hệ và ảnh đại diện signed by Lollyvector SVG15 paths~1.2k nodes30 groups1 image40 KBTự kiểm chứngTải tệp đã ký

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-…"
  }
}
TrườngÝ nghĩa
formatLuôn là lolly-backup. Một file không có trường này bị từ chối với thông báo "not a Lolly backup".
formatVersionBố cục mà gói này được ghi ra. Tăng lên mỗi khi tập hợp phần hoặc cấu trúc thay đổi. Trình đọc không dựa vào trường này để quyết định.
minReaderPhiên bản trình đọc tối thiểu cần có để nhập gói này một cách an toàn. Đây là trường mà trình đọc dựa vào để quyết định.
appId ứng dụng đã tạo ra gói, phục vụ chẩn đoán.
exportedAtDấu thời gian ISO khi gói được tạo.
countsNhững gì trình ghi đã đưa vào, phục vụ hiển thị và kiểm tra tính hợp lý.
integrityTùy chọn. Ánh xạ mọi phần trừ manifest.json tới một digest kiểu SRI sha256-<base64> của các byte chưa nén của nó.

Chính sách phiên bản (tương thích xuôi)

Sự tách biệt giữa formatVersion và minReader là điều cho phép định dạng phát triển mà không bỏ rơi các bản cài đặt cũ:

Quy tắc ngón tay cái cho tác giả: nếu mọi trình đọc hiện có vẫn hành xử đúng khi bỏ qua phần bổ sung của bạn, thì đó là thay đổi bổ sung - tăng formatVersion, giữ nguyên minReader. Ngược lại, hãy tăng minReader.

Tính toàn vẹn

Khi manifest.integrity có mặt, trình đọc xác minh SHA-256 của từng phần được liệt kê trước khi ghi bất cứ thứ gì. Một sự không khớp ("failed its integrity check") hoặc một phần bị thiếu ("incomplete") sẽ hủy toàn bộ quá trình nhập - không có chuyện khôi phục một phần. Điều này bắt được sự hỏng hóc mà một phương thức truyền file có thể gây ra (một lượt AirDrop bị cắt xén, một cổng email mã hóa lại tệp đính kèm, một sector USB bị lỗi).

Tính toàn vẹn được thiết kế theo kiểu nỗ lực tối đa: nó chỉ được ghi ở nơi có Web Crypto (mọi ngữ cảnh trình duyệt an toàn và Node hiện đại), và chỉ được xác minh khi cả bản đồ lẫn Web Crypto đều có mặt. Một gói không có bản đồ - ví dụ một gói từ trước khi tính toàn vẹn tồn tại - vẫn được nhập không thay đổi. "Không thể xác minh" không bao giờ bị coi là "hỏng".

Manifest không liệt kê chính nó lẫn README lolly.txt được tạo lại. Các digest bao phủ những phần mà manifest bảo chứng.

Ngữ nghĩa của việc nhập

Nhập là một hợp nhất, không bao giờ là thay thế toàn bộ:

Các phiên đã lưu tự động liên kết lại với hình ảnh của chúng: tham chiếu tài sản được giữ theo id, và cầu nối sẽ phân giải lại chúng sau khi các hình ảnh đã tải lên được khôi phục (dù sao thì nó cũng phải làm vậy, vì URL blob: không tồn tại được qua một lần tải lại trang).

Bản tóm tắt nhập báo cáo { profile, sessions, userAssets, prefs, skipped, failedAssets }. failedAssets đếm số tài sản đã tải lên nhưng không thể khôi phục (chẳng hạn bộ nhớ thiết bị đầy). Nó khác với skipped, vốn đếm các phần từ một trình ghi mới hơn tương thích ngược mà bản build này không nhận ra. Giao diện hiển thị skipped ("… · N newer items skipped"), để việc khôi phục trung thực về những gì nó đã bỏ lại.

Khi có file history, bản tóm tắt cũng mang theo assetVersions, fileOperations và failedHistory. Việc cạn dung lượng lưu trữ hoặc xung đột ID bất biến có thể gây ra một lượt khôi phục một phần; giao diện báo cho người dùng biết để giữ lại bản sao lưu gốc. Đồng bộ đám mây không tiến revision đã áp dụng của nó sau một lượt khôi phục một phần hoặc không được hỗ trợ, nên bản chụp vẫn khả dụng để thử lại. Khôi phục không phải là một giao dịch duy nhất trên toàn bộ các kho hồ sơ/phiên/tài sản/lịch sử.

Lịch sử tạo tác (v3)

Các bản sao lưu thủ công từ một máy chủ web có khả năng lưu lịch sử bao gồm revision-history.json với schema { version: 1, documents, revisions, recoveries } riêng của nó. Nó mang theo các ID được giữ lại, các bản chụp đầu vào chính tắc, dấu phiên bản, ảnh xem trước raster và các bản nháp writer riêng biệt. Bộ chuyển đổi lịch sử ghi lại các phiên hiện tại và đầu (head) của chúng trong một giao dịch đọc; sessions.json dùng chính các bản chụp hiện tại đó cho các trình đọc cũ hơn.

Khôi phục kiểm tra SHA-256 và số byte của payload, danh tính duy nhất, quan hệ tài liệu/đầu (head), dòng dõi, dấu thời gian, loại xem trước và các giới hạn trước khi commit kho lưu trữ trong một giao dịch duy nhất. Các tham chiếu cha đã được nén gọn có thể vắng mặt. Công việc hiện hành đang có không bao giờ bị âm thầm thay thế: khi một tác phẩm có ở cả hai bên, bên không được giữ làm hiện hành sẽ trở thành một bản nháp được bảo vệ. Giới hạn truyền 384 MiB của kho lưu trữ được kiểm tra rõ ràng, và các giới hạn lưu trữ được thực thi mà không cắt bớt các checkpoint đã được giữ lại. Toàn bộ bản sao lưu vẫn dùng cách triển khai ZIP trong bộ nhớ và không phải là một kho lưu trữ dạng streaming.

Bản tóm tắt bổ sung thêm revisions và recoveryDrafts, chỉ đếm những gì lượt nhập này đã thêm vào, cùng added, kept, replaced, copies và hidden cho biết mỗi tác phẩm đã được hợp nhất ra sao. Một shell không có khả năng này sẽ khôi phục các phiên thông thường và báo cáo phần lịch sử là bị bỏ qua. Lịch sử hệ thống tệp gốc vẫn chưa được hỗ trợ cho đến khi bộ chuyển đổi của nó cung cấp các giao dịch lịch sử bền vững. Trạng thái khách P2P không có lịch sử bền vững hay kho lưu trữ phục hồi nào.

Đồng bộ bản chụp cá nhân cố tình loại trừ lịch sử tạo tác. Áp dụng một bản chụp vào một tài liệu cục bộ có lịch sử sẽ giữ lại trạng thái làm việc trước đó của nó dưới dạng một bản nháp phục hồi riêng biệt và làm mất hiệu lực token ghi của bất kỳ trình chỉnh sửa đang mở nào. Các checkpoint bất biến của nó vẫn ở lại trên thiết bị. Điều này bảo vệ lịch sử cục bộ trong khi thay thế bản chụp; nó không hợp nhất các lịch sử thiết bị đồng thời.

Các tham chiếu tài sản lịch sử được giữ lại, trong khi việc kết xuất vẫn phân giải tài sản qua thư viện hiện có của đích đến. Kho lưu trữ này chưa đảm bảo byte tài sản cũ hay bản kết xuất công cụ cũ chính xác. Byte của phiên bản tài sản và kết quả tệp tiếp tục di chuyển qua phần sao lưu riêng hiện có của chúng.

Các phiên bản đã lưu và kết quả tệp (v2)

Phần lịch sử tùy chọn chứa { version: 2, assetVersions: [...], operations: [...], batches: [...] }; các trình đọc cũng chấp nhận dạng history-v1 trước đó không có batches. Mỗi bản chụp xác định ID tài sản ổn định và phiên bản chính xác, thời điểm lưu, độ dài byte và SHA-256 dạng hex, cùng một bản ghi tài sản mà _file và _credentialFile tùy chọn của nó trỏ đến các phần nhị phân. Các thao tác mang theo dữ kiện tệp gốc, yêu cầu, báo cáo, dấu thời gian và _file kết quả tùy chọn; tên backend lưu trữ, các handle OPFS và các lease thực thi không di chuyển theo. Các trình đọc chỉ hỗ trợ history-v1 cũ hơn sẽ từ chối phiên bản lịch sử mới trước khi nhập, thay vì âm thầm bỏ qua tư cách thành viên batch.

Các bản kê khai batch ghi lại mọi nguồn đã chọn trước khi xử lý, kể cả các tệp chưa từng được đọc, các thành viên đã hủy, các lần không đặt trước được không gian kết quả và công việc bị gián đoạn. Mỗi thành viên có một ID thao tác ổn định, tham chiếu/dữ kiện nguồn, tên đầu ra được yêu cầu và báo cáo cuối cùng. Một nguồn chưa được đọc có các dữ kiện đã khai báo, không phải một digest bịa ra. Việc nhập xác thực danh tính thành viên và tính nhất quán với bất kỳ báo cáo thao tác nào đi kèm. Các báo cáo batch vẫn khả dụng khi các kết quả riêng lẻ đã bị xóa rõ ràng, nhưng một biên nhận không có nghĩa là byte đầu ra của nó vẫn còn được lưu trữ.

Các trình đọc cũ hơn vẫn chấp nhận envelope v2 (minReader: 1) và khôi phục các phần quen thuộc, tính các phần lịch sử không được hỗ trợ là bị bỏ qua. Khôi phục lịch sử đầy đủ đòi hỏi một shell có bộ chuyển đổi fileHistory; đây là một điểm nối nội bộ của shell, không phải một khả năng HostV1 mới hướng tới công cụ. Khôi phục thật giữa hai thiết bị được bao phủ bởi cổng kiểm tra Chromium cục bộ; việc chấp nhận khôi phục trên Tauri/iOS/Android đã cài đặt vẫn là việc riêng.

Những gì không được mang theo

Đồng hồ đo dung lượng lưu trữ liệt kê chi tiết theo cùng cách phân chia đó. Saved sessions, My images và File results & versions được mang theo trong một gói. Asset cache, tool previews và offline pins bên dưới chúng đều có thể tạo lại được, nên chúng ở lại.

Đồng hồ đo dung lượng lưu trữ chia dữ liệu của thiết bị này thành các danh mục có tên, với Saved sessions và My images được theo dõi riêng biệt so với Asset cache, ở đây trên một bản cài đặt mới nơi mọi danh mục vẫn còn trống signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBTự kiểm chứngTải tệp đã kýĐồng hồ đo dung lượng lưu trữ chia dữ liệu của thiết bị này thành các danh mục có tên, với Saved sessions và My images được theo dõi riêng biệt so với Asset cache, ở đây trên một bản cài đặt mới nơi mọi danh mục vẫn còn trống signed by Lollyvector SVG37 paths~4.9k nodes85 groups65 KBTự kiểm chứngTải tệp đã ký

Cam kết xuyên shell

data-transfer.ts chỉ đọc và ghi thông qua cầu nối năng lực (capability bridge) (host.profile, host.state, host.assets) và các tùy chọn localStorage dùng chung. Cùng một module đọc và ghi envelope chung trên web và Tauri, qua IndexedDB hoặc bộ nhớ hệ thống tệp. Các phần lịch sử tùy chọn chỉ xuất hiện ở nơi có bộ chuyển đổi tương ứng; một phần không được hỗ trợ sẽ được báo cáo là bị bỏ qua khi nhập. Bộ test headless kiểm chứng các phần chung với một cầu nối trong bộ nhớ, trong khi các giao dịch lịch sử cũng có các bài test trình duyệt thật.

Hai shell nằm ngoài đảm bảo đó, vì những lý do khác nhau:

Các điểm mở rộng dự phòng

Phong bì dữ liệu được thiết kế là một manifest cộng với một tập các phần được đặt tên, để các loại dữ liệu di động mới có thể đi kèm sau này mà không gây thay đổi phá vỡ tương thích. Chúng được thêm vào như các phần bổ sung (formatVersion mới, minReader không đổi), và trình đọc hiện tại bỏ qua những gì nó không nhận ra. Những phần này chưa được xây dựng. Tên gọi được dự phòng ở đây để định dạng vẫn nhất quán khi chúng ra mắt.

Bất cứ thứ gì nằm ngoài các tên dự phòng này và các phần nêu trên, đối với trình đọc, đều là một phần không xác định: được giữ nguyên và tính vào skipped.

Tham khảo