all: delete the code nothing calls
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 8s
CI & Build / Python tests (push) Successful in 10s
CI & Build / integration (push) Failing after 1m21s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m47s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m48s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m39s
Desktop (Tauri) / Update manifest (push) Successful in 3s
Android / Kotlin + Rust (APK) (push) Successful in 8m37s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Build now, or wait for Android? (push) Successful in 2s
Android / Build, or is the channel already serving this? (push) Successful in 3s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
CI & Build / Web typecheck and unit tests (push) Successful in 8s
CI & Build / Python tests (push) Successful in 10s
CI & Build / integration (push) Failing after 1m21s
CI & Build / Build & push image (push) Skipped
Desktop (Tauri) / Web tests, clippy, Rust tests and rustfmt (push) Successful in 2m47s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 2m48s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 3m39s
Desktop (Tauri) / Update manifest (push) Successful in 3s
Android / Kotlin + Rust (APK) (push) Successful in 8m37s
From the audit (#5178). Each was unreachable from every client: - Checklist add-item and delete-item: REST POST /items and DELETE /items/<id>, the Tauri commands, the store, rest and local adapters, the core's add_item/delete_item, set_item_text and remove_item, and the FFI exports. Adding, rewording and removing an item are body edits in every editor. The checked toggle stays, and its rewriter is simpler without the drop branch. - Manual unfurl: POST /unfurl and its adapters. Previews arrive in the background after a save (unfurl_queue). - The /api/config `android_client` key, android_release() and the APK_NAME/MANIFEST_NAME aliases. Phones poll /api/client/android. - users.email_verified and users.avatar_path (migration 0037). Nothing set the first or read the second; the SMTP reset never checked verification. - derive::extract_tags (only tests used it; the shared fixture now runs through extract_tag_spans), the unused check and link icons, and the unused editor_add_item string. - The blob scheme is renamed tsblob -> inkblob. URLs are built as notes are read, so nothing stored carries the old one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// Argument keys are camelCase; Tauri converts them to the Rust commands' snake_case
|
||||
// parameters (e.g. labelIds -> label_ids). A few operations have no offline meaning
|
||||
// yet (account auth, device linking, URL unfurl) — those reject with a clear message
|
||||
// yet (account auth, device linking) — those reject with a clear message
|
||||
// rather than silently failing; the board, editor, attachments, capture, filters,
|
||||
// labels, checklists, reminders, import and export all work fully offline.
|
||||
|
||||
@@ -55,9 +55,7 @@ export const local: Repo = {
|
||||
completeReminder: (id) => invoke<Note>("notes_complete_reminder", { id }),
|
||||
snoozeReminder: (id, minutes) => invoke<Note>("notes_snooze_reminder", { id, minutes }),
|
||||
setLabels: (id, labelIds) => invoke<Note>("notes_set_labels", { id, labelIds }),
|
||||
addItem: (id, text) => invoke<Note>("notes_add_item", { id, text }),
|
||||
updateItem: (id, itemId, changes) => invoke<Note>("notes_update_item", { id, itemId, changes }),
|
||||
deleteItem: (id, itemId) => invoke<Note>("notes_delete_item", { id, itemId }),
|
||||
// Kept on this device and uploaded by the next sync once linked (#5168). The bytes
|
||||
// go as the raw IPC body; the name is percent-encoded because a header carries
|
||||
// only ASCII.
|
||||
@@ -70,7 +68,6 @@ export const local: Repo = {
|
||||
},
|
||||
}),
|
||||
deleteAttachment: (id, attId) => invoke<Note>("notes_delete_attachment", { id, attId }),
|
||||
unfurl: () => Promise.reject<Note>(new Error(NEEDS_SERVER)),
|
||||
deletePreview: (id, previewId) => invoke<Note>("notes_delete_preview", { id, previewId }),
|
||||
// The archive crosses as raw bytes, as an attachment does.
|
||||
import: async (file) => invoke<ImportResult>("notes_import", new Uint8Array(await file.arrayBuffer())),
|
||||
|
||||
@@ -40,9 +40,9 @@ export type NoteChanges = Partial<
|
||||
Pick<Note, "body" | "pinned" | "archived" | "remind_at" | "recurrence">
|
||||
>;
|
||||
|
||||
/** The one item change that isn't typing in the body: ticking its box. */
|
||||
export interface ChecklistItemChanges {
|
||||
text?: string;
|
||||
checked?: boolean;
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,12 +131,9 @@ export interface NotesRepo {
|
||||
completeReminder(id: string): Promise<Note>;
|
||||
snoozeReminder(id: string, minutes: number): Promise<Note>;
|
||||
setLabels(id: string, labelIds: string[]): Promise<Note>;
|
||||
addItem(id: string, text: string): Promise<Note>;
|
||||
updateItem(id: string, itemId: string, changes: ChecklistItemChanges): Promise<Note>;
|
||||
deleteItem(id: string, itemId: string): Promise<Note>;
|
||||
uploadAttachment(id: string, file: File): Promise<Note>;
|
||||
deleteAttachment(id: string, attId: string): Promise<Note>;
|
||||
unfurl(id: string, url: string): Promise<Note>;
|
||||
deletePreview(id: string, previewId: string): Promise<Note>;
|
||||
import(file: File): Promise<ImportResult>;
|
||||
/** Save every note as a zip. Resolves to the path it was saved at, or null when
|
||||
|
||||
@@ -84,13 +84,10 @@ export const rest: Repo = {
|
||||
completeReminder: (id) => api.post<Note>(`/api/notes/${id}/reminder/complete`),
|
||||
snoozeReminder: (id, minutes) => api.post<Note>(`/api/notes/${id}/reminder/snooze`, { minutes }),
|
||||
setLabels: (id, labelIds) => api.put<Note>(`/api/notes/${id}/labels`, { label_ids: labelIds }),
|
||||
addItem: (id, text) => api.post<Note>(`/api/notes/${id}/items`, { text }),
|
||||
updateItem: (id, itemId, changes: ChecklistItemChanges) =>
|
||||
api.patch<Note>(`/api/notes/${id}/items/${itemId}`, changes),
|
||||
deleteItem: (id, itemId) => api.del<Note>(`/api/notes/${id}/items/${itemId}`),
|
||||
uploadAttachment: (id, file) => api.postForm<Note>(`/api/notes/${id}/attachments`, fileForm(file)),
|
||||
deleteAttachment: (id, attId) => api.del<Note>(`/api/notes/${id}/attachments/${attId}`),
|
||||
unfurl: (id, url) => api.post<Note>(`/api/notes/${id}/unfurl`, { url }),
|
||||
deletePreview: (id, previewId) => api.del<Note>(`/api/notes/${id}/previews/${previewId}`),
|
||||
import: (file) => api.postForm<ImportResult>("/api/notes/import", fileForm(file)),
|
||||
// A same-origin GET with the session cookie; the browser saves the attachment
|
||||
|
||||
@@ -13,7 +13,6 @@ const paths: Record<string, string> = {
|
||||
tag: '<path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"/><circle cx="7.5" cy="7.5" r=".5" fill="currentColor"/>',
|
||||
pencil: '<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"/><path d="m15 5 4 4"/>',
|
||||
plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
|
||||
check: '<path d="M20 6 9 17l-5-5"/>',
|
||||
checkbox: '<rect width="18" height="18" x="3" y="3" rx="2"/><path d="m9 12 2 2 4-4"/>',
|
||||
image: '<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/>',
|
||||
bell: '<path d="M10.268 21a2 2 0 0 0 3.464 0"/><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"/>',
|
||||
@@ -27,7 +26,6 @@ const paths: Record<string, string> = {
|
||||
device: '<rect width="14" height="20" x="5" y="2" rx="2" ry="2"/><path d="M12 18h.01"/>',
|
||||
sync: '<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M3 21v-5h5"/>',
|
||||
paperclip: '<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"/>',
|
||||
link: '<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',
|
||||
filter: '<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>',
|
||||
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
||||
copy: '<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',
|
||||
|
||||
@@ -49,10 +49,6 @@ export interface PublicConfig {
|
||||
// Every client this server holds, keyed by platform id. Absent on a server that
|
||||
// holds none, and absent on the desktop's own offline config — the Tauri build
|
||||
// answers `config_get` locally and has no clients to hand out.
|
||||
//
|
||||
// `/api/config` also carries `android_client`, which is NOT declared here: it
|
||||
// exists for phones in the field polling for their own update, not for this app,
|
||||
// and reading it here would be a second path to the same fact.
|
||||
clients?: Record<string, ClientRelease>;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,18 +184,10 @@ export const useNotesStore = defineStore("notes", () => {
|
||||
reconcile(await repo.notes.setLabels(id, labelIds));
|
||||
}
|
||||
|
||||
async function addItem(id: string, text: string): Promise<void> {
|
||||
reconcile(await repo.notes.addItem(id, text));
|
||||
}
|
||||
|
||||
async function updateItem(id: string, itemId: string, changes: { text?: string; checked?: boolean }): Promise<void> {
|
||||
async function updateItem(id: string, itemId: string, changes: { checked: boolean }): Promise<void> {
|
||||
reconcile(await repo.notes.updateItem(id, itemId, changes));
|
||||
}
|
||||
|
||||
async function deleteItem(id: string, itemId: string): Promise<void> {
|
||||
reconcile(await repo.notes.deleteItem(id, itemId));
|
||||
}
|
||||
|
||||
async function uploadAttachment(id: string, file: File): Promise<void> {
|
||||
reconcile(await repo.notes.uploadAttachment(id, file));
|
||||
}
|
||||
@@ -204,10 +196,6 @@ export const useNotesStore = defineStore("notes", () => {
|
||||
reconcile(await repo.notes.deleteAttachment(id, attId));
|
||||
}
|
||||
|
||||
async function unfurl(id: string, url: string): Promise<void> {
|
||||
reconcile(await repo.notes.unfurl(id, url));
|
||||
}
|
||||
|
||||
async function deletePreview(id: string, previewId: string): Promise<void> {
|
||||
reconcile(await repo.notes.deletePreview(id, previewId));
|
||||
}
|
||||
@@ -299,12 +287,9 @@ export const useNotesStore = defineStore("notes", () => {
|
||||
snoozeReminder,
|
||||
saveEdit,
|
||||
setLabels,
|
||||
addItem,
|
||||
updateItem,
|
||||
deleteItem,
|
||||
uploadAttachment,
|
||||
deleteAttachment,
|
||||
unfurl,
|
||||
deletePreview,
|
||||
importNotes,
|
||||
fetchOne,
|
||||
|
||||
@@ -6,7 +6,6 @@ export interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
display_name: string;
|
||||
email_verified: boolean;
|
||||
is_admin: boolean;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user