Files
inkwell/core/testdata/portable.json
T
bvandeusenandClaude Opus 5.5 5989ffc1c6
CI & Build / Build now, or wait for Android? (push) Successful in 4s
Android / Build, or is the channel already serving this? (push) Successful in 4s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 12s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Python tests (push) Successful in 13s
CI & Build / integration (push) Successful in 48s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 4m26s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 3m32s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 4m10s
Desktop (Tauri) / Update manifest (push) Successful in 4s
Android / Kotlin + Rust (APK) (push) Successful in 12m42s
desktop: Import and Export work offline; the menu toggle is reachable; errors say why
Export and Import were a link to the server and a reject("needs a server") on the
desktop. Both now run in the core with no server:

- core/src/local/portable.rs builds the same zip the server writes (notes.json,
  a Markdown file per note, each attachment this device holds) and reads either
  export marker or a Google Keep Takeout zip, with the server's decompression
  budget and an all-or-nothing transaction. Export saves to Downloads (no new
  plugin) and the sidebar says where; Import takes the archive as raw IPC bytes.
- core/testdata/portable.json pins the format for both copies: the server runs
  its Keep and native readers against it (test_portable_fixture.py) and checks
  its real export's keys (test_integration.py); the core runs the same cases.
- Found on the way: both importers skipped a Keep note that is only a photo as
  "empty". It now imports, on the server and in the core.
- New dependency, approved: `zip` (deflate only) plus `flate2` on its pure-Rust
  backend, both already in the lockfile.

The AppImage applications-menu toggle moves from Account, which the desktop
never shows, to the Sync page; the first-run prompt now says so.

errorMessage (#5236) replaces the hand-rolled `.error ?? …` / `.message ?? e`
reads at the remaining catch sites, so a desktop failure shows its real reason.

Task #5170.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 11:36:42 -04:00

147 lines
4.8 KiB
JSON

{
"_about": [
"The export/import format, pinned for every implementation of it.",
"Read by the server (tests/test_portable_fixture.py, and the export check in test_integration.py) and by the core (local/portable.rs). The desktop's offline Export and Import are the core's copy; a backup taken on one surface has to restore on the other.",
"`keep` and `native` are notes as they arrive, with the spec each importer must make of them. `export` names the keys an export writes, at the top of notes.json and on each note. A difference between the server and the core here is a backup that loses something on the way across."
],
"keep": [
{
"about": "A list note keeps its text as well as its items; annotation URLs are folded into the body; the colour is read past.",
"dir": "Takeout/Keep",
"note": {
"title": "Groceries",
"textContent": "for the weekend",
"listContent": [
{ "text": "Milk", "isChecked": false },
{ "text": "Eggs", "isChecked": true }
],
"annotations": [{ "url": "https://example.com/recipe" }],
"labels": [{ "name": "shopping" }],
"color": "TEAL",
"isPinned": true,
"isArchived": false,
"isTrashed": false,
"createdTimestampUsec": 1600000000000000,
"userEditedTimestampUsec": 1600000100000000,
"attachments": [
{ "filePath": "photo.jpg", "mimetype": "image/jpeg" },
{ "filePath": "scan.png" }
]
},
"spec": {
"title": "Groceries",
"body": "for the weekend\n\nhttps://example.com/recipe",
"pinned": true,
"archived": false,
"trashed": false,
"labels": ["shopping"],
"items": [
{ "text": "Milk", "checked": false },
{ "text": "Eggs", "checked": true }
],
"attachments": [
{ "file": "Takeout/Keep/photo.jpg", "mime": "image/jpeg" },
{ "file": "Takeout/Keep/scan.png", "mime": "image/png" }
],
"created_at": "2020-09-13T12:26:40Z",
"updated_at": "2020-09-13T12:28:20Z"
}
},
{
"about": "A trashed, archived text note with no timestamps.",
"dir": "",
"note": {
"textContent": "old idea",
"isArchived": true,
"isTrashed": true
},
"spec": {
"title": null,
"body": "old idea",
"pinned": false,
"archived": true,
"trashed": true,
"labels": [],
"items": [],
"attachments": [],
"created_at": null,
"updated_at": null
}
}
],
"native": [
{
"about": "A current export: the checklist is already in the body, a reminder and recurrence come across, and the pre-M315 colour is read past.",
"note": {
"id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"display_title": "Trip",
"body": "Trip\n\n- [ ] passport",
"color": "blue",
"pinned": true,
"archived": false,
"remind_at": "2026-11-01T09:00:00+00:00",
"recurrence": "weekly",
"created_at": "2026-07-19T00:00:00+00:00",
"updated_at": "2026-07-20T08:30:00.250000+00:00",
"labels": ["travel"],
"attachments": [{ "file": "attachments/6ba7b810/0/ticket.pdf", "mime": "application/pdf" }]
},
"spec": {
"title": null,
"body": "Trip\n\n- [ ] passport",
"pinned": true,
"archived": false,
"trashed": false,
"remind_at": "2026-11-01T09:00:00Z",
"recurrence": "weekly",
"labels": ["travel"],
"items": [],
"attachments": [{ "file": "attachments/6ba7b810/0/ticket.pdf", "mime": "application/pdf" }],
"created_at": "2026-07-19T00:00:00Z",
"updated_at": "2026-07-20T08:30:00.250Z"
}
},
{
"about": "An export from before M304 carries a title and a separate items array; an unknown recurrence is dropped.",
"note": {
"title": "shopping",
"body": "",
"recurrence": "fortnightly",
"items": [{ "text": "milk", "checked": true }]
},
"spec": {
"title": "shopping",
"body": "",
"pinned": false,
"archived": false,
"trashed": false,
"remind_at": null,
"recurrence": null,
"labels": [],
"items": [{ "text": "milk", "checked": true }],
"attachments": [],
"created_at": null,
"updated_at": null
}
}
],
"export": {
"document": ["app", "version", "exported_at", "labels", "notes"],
"note": [
"id",
"display_title",
"body",
"pinned",
"archived",
"remind_at",
"recurrence",
"created_at",
"updated_at",
"labels",
"attachments"
],
"label": ["name", "color"],
"attachment": ["file", "mime"]
}
}