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 → Moving to another deviceを参照してください。実装はshells/web/src/data-transfer.tsで、tests/data-transfer.test.tsがラウンドトリップの契約を固定しています。
範囲。 バンドルが運ぶのはユーザーデータであり、ツールではありません。ツールとカタログアセットは別途同期され、転送先にはすでに存在している(最悪の場合はより新しいバージョンで)ことが前提です。インポートがツールをインストールしたりアップグレードしたりすることは決してありません。
目標
- 1つのフォーマット、すべてのシェルで。 同じバイト列がWeb PWA、Tauriデスクトップ/モバイルアプリ、将来のあらゆるシェルによって生成・消費されます。バンドルが契約であり、各シェルのケイパビリティブリッジがその背後にあるプラットフォーム固有のアダプターです。
- 転送に耐える。 転送中に破損・切り詰められたバンドルは、インポート時にはっきりと失敗し、決して中途半端に復元しません。
- このバージョンより長持ちする。 古いアプリでも、新しいバンドルの認識可能な部分はインポートできます。本当に互換性を破る変更は、明確に拒否されます。
- 安全にマージできる。 すでに使用中のインストールへのインポートが、バンドルに含まれていなかったものを消すことは決してありません。
エンベロープ
バンドルは通常の .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> | アセットごと | アセットの生バイト(画像・フォントファイル)。無圧縮で保存(すでに圧縮済みのフォーマットのため)。拡張子は表示上のもの。正式なMIMEは assets.json 側が権威を持つ。 |
prefs.json | はい | ユーザー所有のローカル環境設定: theme、sidebarWidth、ct-metrics のアクティビティ集計。 |
lolly.txt | はい | Lollyを使わずzipを開いた人向けに、バンドルの内容(件数、プロフィール、ファイル名)を人間可読な形でまとめたもの。エクスポートのたびに再生成され、インポート時には認識されるため、スキップされたパートとしてカウントされることはない。整合性マップの後に書き込まれるため、その対象外となる。 |
バンドルはあえて通常の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。これがないファイルは「not a Lolly backup」として拒否される。 |
formatVersion | このバンドルが書き込まれた際のレイアウト。パート構成や形状の変更のたびに繰り上がる。リーダーはこれをゲート条件にはしない。 |
minReader | このバンドルを安全にインポートするために必要な最小のリーダーバージョン。リーダーがゲート条件とするのはこのフィールド。 |
app | 診断用の、生成したアプリのid。 |
exportedAt | バンドルが作成されたISOタイムスタンプ。 |
counts | 書き込み側が入れた内容(表示と整合性チェック用)。 |
integrity | 任意。manifest.json を除くすべてのパートを、その無圧縮バイトの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 READMEも一覧に含めません。ダイジェストが対象とするのは、マニフェストが保証するパートのみです。
インポートのセマンティクス
インポートはマージ・上書きであり、全置換になることは決してありません。
- 転送先の既存データはそのまま残ります。
- 衝突するキー - プロフィール、セッションスロット、アップロード画像のidなど - はインポートされたコピーに置き換えられます。
- バンドルに含まれていなかったものには一切手が付きません。転送先にはあってもバンドルにはなかったセッションは、インポート後も残ります。
保存済みセッションは画像に自動的に再リンクされます:アセット参照はidで保持され、アップロード画像が復元された後にブリッジがそれらを再解決します(blob: URLはリロードを跨いで残らないため、いずれにせよ必要な処理です)。
インポートのサマリーは { profile, sessions, userAssets, prefs, skipped, failedAssets } を報告します。failedAssets は復元できなかったアップロード済みアセットの数です(例えばデバイスのストレージが満杯の場合など)。これは skipped とは別物で、skipped は前方互換な新しいライターに由来し、このビルドが認識しなかったパートの数を表します。UIは skipped を表示するため(「… · N newer items skipped」)、復元がどこを取りこぼしたかについて正直です。
転送されないもの
- カタログキャッシュ(ダウンロード済みのアセットメタデータとblob、ツールインデックス) - 転送先で無償で再同期される。
- ツールとブランドアセット - 対象外であり、転送先にはすでに存在していることが前提。
blob:/ オブジェクトURL - 読み込み時にブリッジが再生成する。- エクスポート連番カウンター - 日単位のダウンロード命名カウンター(
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 prefs だけを通じて読み書きします。ブリッジが唯一の接点であるため、下層のストレージがシェルごとに異なっていても - web では IndexedDB、Tauri ではファイルシステム - 同じモジュールがどのシェルでもバイト単位で同一のバンドルを生成します。Tauri シェルはこのモジュールをそのまま再利用しており、異なるのは host.state の実装だけです。ヘッドレステストはインメモリのブリッジに対してラウンドトリップ全体を検証しており、そのためこのテストがすべてのシェルの代表となります。
この保証の外にあるシェルが2つあり、それぞれ理由が異なります。
- ワンショットの CLI は保持するものがありません - その状態は呼び出しごとにインメモリで一時的なものです。
- TUI は状態を永続化しており(
~/.lolly: セッション、フォルダ、プロフィール)、その Profile ビューはバックアップも取れますが、書き出すのは独自のよりシンプルなアーカイブです。セッションごとのsessions/<slot>.jsonに加えてprofile.jsonとfolders.jsonがあるだけで、マニフェストもformatVersion/minReaderも整合性マップもありません。この形式ではインポートできず - リーダーは「Lolly のバックアップではありません」として拒否します - しかも紛らわしいことに似た名前(lolly-backup-<stamp>.zip)を使っています。両者の統一は既知のギャップです。
予約された拡張ポイント
エンベロープはマニフェストと名前付きパーツの集合として設計されているため、新しい種類の移植可能なデータを破壊的変更なしに後から乗せられます。それらは追加的なパーツとして組み込まれ(新しい formatVersion、同じ minReader)、現在のリーダーは認識しないものをスキップします。これらはロードマップにあるもので、まだ実装されていません。将来これらが導入されたときにフォーマットの一貫性を保つため、名前だけをここで予約しています。
tokens.json- デザイントークン。 W3C DTCG のデザイントークンドキュメント(Penpot がインポート/エクスポートする形式 -$value/$type/$descriptionを持つトークンをグループ、セット、テーマに整理したもの)。バンドル内のトークンセットにより、ユーザーはセッションと一緒にブランドのプリミティブをインストール間で移動できます。長期的には、取り込まれたトークンセットはツールやパレットアセットが参照する第一級のソースになります。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- Host API を参照してください。