Skip to content

fix(tauri): sanitize db path for Tauri event-name validation#956

Closed
msvargas wants to merge 1 commit into
powersync-ja:mainfrom
barvaz-engineering:fix/tauri-event-name-sanitize
Closed

fix(tauri): sanitize db path for Tauri event-name validation#956
msvargas wants to merge 1 commit into
powersync-ja:mainfrom
barvaz-engineering:fix/tauri-event-name-sanitize

Conversation

@msvargas
Copy link
Copy Markdown
Contributor

Problem

Tauri validates event names against the pattern [a-zA-Z0-9\-/:_]. The Tauri SDK uses the resolved database file path as the event-name key (e.g. table-updates:/Library/Application Support/com.barvaz.lacaja-ai/tenant.db). A typical macOS app data path contains dots (.db extension, bundle ID components) and spaces (e.g. Application Support) — both characters are rejected by Tauri's event system, causing:

Error: Event name must include only alphanumeric characters, '-', '/', ':' and '_'.

This breaks any app that:

  • uses a dbFilename with a .db extension, or
  • resolves dbLocationAsync to a directory that contains spaces or dots (which is the case for the standard macOS app-data directories).

The result is that table-update and sync-status listeners are never registered, so the database appears frozen from JavaScript's perspective.

Fix

Add a sanitize_event_name helper in packages/tauri/src/database.rs and a mirrored sanitizeEventKey private method in packages/tauri/guest-js/database.ts. Both replace every character outside [a-zA-Z0-9\-/:_] with _.

Both sides use the same sanitization rule, so the Rust emitter and the JavaScript listener always produce identical event-name keys — the mapping is purely cosmetic and does not affect routing.

packages/tauri/src/database.rs — new helper + usage:

fn sanitize_event_name(name: &str) -> String {
    name.chars()
        .map(|c| {
            if c.is_ascii_alphanumeric() || matches!(c, '-' | '/' | ':' | '_') {
                c
            } else {
                '_'
            }
        })
        .collect()
}

// In TauriDatabaseState::new:
let sanitized = sanitize_event_name(name);
let event_key = format!("table-updates:{}", sanitized);
// ...
let event_key = format!("sync-status:{}", sanitized);

packages/tauri/guest-js/database.ts — mirrored helper + usage:

private sanitizeEventKey(key: string): string {
  return key.replace(/[^a-zA-Z0-9\-/:_]/g, '_');
}

// In _initialize():
const eventKey = this.sanitizeEventKey(path);
this.tableUpdateListener = await listen<string[]>(`table-updates:${eventKey}`, ...);
this.syncStatusListener = await listen<SyncStatusOptions>(`sync-status:${eventKey}`, ...);

cc @simolus3 (author of the Tauri SDK, PR #902)

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 12, 2026

⚠️ No Changeset found

Latest commit: aaed910

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@simolus3
Copy link
Copy Markdown
Contributor

Thanks for your contribution! I'd like to close this in favor of generating integer keys for events, which should be safer and simpler overall (#957).

@simolus3 simolus3 closed this May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants