Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2d5eef7
m2(deps): add db foundation dependencies
h4yfans Apr 24, 2026
2e580af
m2(db): add AppState Db and AppError
h4yfans Apr 24, 2026
d5e8a4d
m2(migrations): add runner and placeholders
h4yfans Apr 25, 2026
6bae9e1
m2(migrations): port 0000 core schema (projects/statuses/tasks/task_n…
h4yfans Apr 25, 2026
a317b2b
m2(migrations): port 0001-0004 (bookmarks, inbox extensions, suggesti…
h4yfans Apr 25, 2026
13249ed
m2(migrations): port 0005-0009 (inbox alters, note_positions, tag_def…
h4yfans Apr 25, 2026
2d3713e
m2(migrations): port 0010-0014 (sync clocks on tasks/inbox/saved_filt…
h4yfans Apr 25, 2026
ae50329
m2(migrations): port 0015-0019 (project/tag clocks, field_clocks, rec…
h4yfans Apr 25, 2026
9625419
m2(migrations): port 0020-0028 hand-written (search_reasons/inbox_job…
h4yfans Apr 25, 2026
e07d488
m2(migrations): add full-apply integration tests (table set + field_c…
h4yfans Apr 25, 2026
91d8b01
m2(db): add Project/Status/Task structs with from_row helpers
h4yfans Apr 25, 2026
328e4b1
m2(db): add NoteMetadata/NotePosition/PropertyDefinition structs
h4yfans Apr 25, 2026
5e83a4f
m2(migrations): toggle FK off during replay; run integration tests by…
h4yfans Apr 25, 2026
3a42829
m2(db): add calendar_{events,sources,external_events,bindings} structs
h4yfans Apr 25, 2026
8fb44f4
m2(db): add inbox/bookmarks/reminders/tag_definitions/folder_configs …
h4yfans Apr 25, 2026
4dd8d98
m2(migrations): fix concurrent-replay race + FK pragma restore on error
h4yfans Apr 25, 2026
7a712d1
m2(db): add sync_{queue,devices,state,history}/search_reasons structs
h4yfans Apr 25, 2026
316e0f1
m2(settings): settings_get/set/list commands + 5 Rust tests
h4yfans Apr 25, 2026
99cfa01
m2(bindings): regenerate with 22 domain types + settings commands
h4yfans Apr 25, 2026
53b2cfc
m2(renderer): swap settings_* mock for real invoke; useSettings hook …
h4yfans Apr 25, 2026
19e2cd4
m2(settings): migrate useGeneralSettings onto real settings_get/set K…
h4yfans Apr 25, 2026
0da81ae
m2(devx): add MEMRY_DEVICE=A/B dev scripts
h4yfans Apr 25, 2026
fa249b2
m2(devx): add dev scripts and parity audit
h4yfans Apr 25, 2026
ffa1835
m2(bench): 1000-row list query p50 < 20ms acceptance test
h4yfans Apr 25, 2026
52e14e6
m2(settings): implement settings_get/set/list commands with SQLite ba…
h4yfans Apr 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions apps/desktop-tauri/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"type": "module",
"scripts": {
"dev": "tauri dev",
"dev:a": "MEMRY_DEVICE=A tauri dev",
"dev:b": "MEMRY_DEVICE=B tauri dev",
"build": "tauri build",
"preview": "vite preview",
"lint": "pnpm exec eslint --cache .",
Expand All @@ -17,12 +19,16 @@
"test:e2e": "playwright test",
"cargo:check": "cd src-tauri && cargo check",
"cargo:clippy": "cd src-tauri && cargo clippy -- -D warnings",
"cargo:test": "cd src-tauri && cargo test",
"cargo:test": "cd src-tauri && cargo test --features test-helpers",
"cargo:fmt": "cd src-tauri && cargo fmt",
"bindings:generate": "tsx scripts/generate-bindings.ts",
"bindings:check": "tsx scripts/check-bindings.ts",
"capability:check": "tsx scripts/capability-sanity-check.ts",
"port:audit": "tsx scripts/port-audit.ts"
"port:audit": "tsx scripts/port-audit.ts",
"command:parity": "tsx scripts/command-parity-audit.ts",
"db:reset": "bash scripts/dev-reset.sh",
"db:new-migration": "tsx scripts/new-migration.ts",
"db:schema-diff": "tsx scripts/schema-diff.ts"
},
"dependencies": {
"@ai-sdk/anthropic": "^3.0.58",
Expand Down Expand Up @@ -147,13 +153,15 @@
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@testing-library/user-event": "^14.6.1",
"@types/better-sqlite3": "^7.6.13",
"@types/node": "^25.2.2",
"@types/react": "^19.2.13",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^5.1.3",
"@vitest/coverage-v8": "^4.0.18",
"@vitest/ui": "^4.0.18",
"autoprefixer": "^10.4.24",
"better-sqlite3": "^12.6.2",
"eslint": "^9.39.2",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^7.0.1",
Expand Down
130 changes: 130 additions & 0 deletions apps/desktop-tauri/scripts/command-parity-audit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { describe, expect, it } from 'vitest'

import {
extractBindingsCommands,
extractElectronChannels,
extractForwarderDomains,
extractGenerateHandlerCommands,
extractInvokeLiterals,
extractMockRouteKeys,
} from './command-parity-audit'

describe('extractInvokeLiterals', () => {
it('returns the literal string passed to invoke()', () => {
// #given a renderer file
const src = "await invoke('settings_get', { key: 'a' })"

// #when scanning for literals
const found = extractInvokeLiterals(src)

// #then the command name is captured
expect(found).toEqual(['settings_get'])
})

it('captures generic-typed invoke<T>(name)', () => {
// #given a renderer file using the typed invoke
const src = "const x = await invoke<Foo>('notes_list', { folder })"

// #when scanning for literals
const found = extractInvokeLiterals(src)

// #then the command name is captured
expect(found).toEqual(['notes_list'])
})

it('ignores non-string-literal invoke calls', () => {
// #given dynamic invoke usage
const src = 'await invoke(name, args)'

// #when scanning for literals
const found = extractInvokeLiterals(src)

// #then dynamic calls do not produce a literal
expect(found).toEqual([])
})
})

describe('extractForwarderDomains', () => {
it('captures the domain prefix from createInvokeForwarder', () => {
// #given a service module wires a forwarder
const src = "createInvokeForwarder<NotesAPI>('notes')"

// #when scanning for forwarder domains
const found = extractForwarderDomains(src)

// #then the domain prefix is captured
expect(found).toEqual(['notes'])
})
})

describe('extractMockRouteKeys', () => {
it('returns top-level route keys from a Routes object literal', () => {
// #given a mock module with two top-level routes and one nested object
const src = [
"export const updaterRoutes: MockRouteMap = {",
' updater_get_state: async () => state,',
' updater_check_for_updates: async () => state,',
' meta: { unrelated: 1 }',
'}',
].join('\n')

// #when extracting keys
const found = extractMockRouteKeys(src)

// #then only the top-level keys with the route shape come back
expect(found.sort()).toEqual(['meta', 'updater_check_for_updates', 'updater_get_state'])
})
})

describe('extractGenerateHandlerCommands', () => {
it('extracts the last segment of every entry in generate_handler!', () => {
// #given a Tauri lib.rs handler list
const src = [
'tauri::generate_handler![',
' commands::settings::settings_get,',
' commands::settings::settings_set,',
' commands::lifecycle::notify_flush_done,',
']',
].join('\n')

// #when parsing the macro body
const found = extractGenerateHandlerCommands(src)

// #then we get the bare command names
expect(found.sort()).toEqual(['notify_flush_done', 'settings_get', 'settings_set'])
})
})

describe('extractBindingsCommands', () => {
it('captures __TAURI_INVOKE("name") calls from the generated bindings', () => {
// #given a specta-generated bindings snippet
const src = `
settingsGet: () => __TAURI_INVOKE("settings_get", { input }),
notifyFlushDone: () => __TAURI_INVOKE("notify_flush_done"),
`

// #when parsing it
const found = extractBindingsCommands(src)

// #then both names are reported
expect(found.sort()).toEqual(['notify_flush_done', 'settings_get'])
})
})

describe('extractElectronChannels', () => {
it('captures kebab-style "domain:method" entries from generated-ipc-invoke-map.ts', () => {
// #given a snippet of the Electron generated map
const src = [
'export interface MainIpcInvokeHandlers {',
' "auth:request-otp": (...args: []) => Awaited<unknown>',
' "calendar:list-events": (...args: []) => Awaited<unknown>',
'}',
].join('\n')

// #when extracting channels
const found = extractElectronChannels(src)

// #then both channels surface
expect(found.sort()).toEqual(['auth:request-otp', 'calendar:list-events'])
})
})
Loading
Loading