Skip to content

Commit 0d84e4e

Browse files
committed
Bugfix: SMB "Connect directly" login dialog shows server name
- Add `rename_all_fields = "camelCase"` to `UpgradeResult` so `display_name`/`username_hint` ship as `displayName`/`usernameHint`. Was rendering `Sign in to "undefined/naspi"` and silently skipping the username pre-fill. - New `ipc-enum-camelcase` check scans `specta::Type` enums with `rename_all = "camelCase"` and struct variants, flags any missing `rename_all_fields`. 4 other enums also lacked it (all single-word fields, wire-identical); fixed for consistency. - Document the serde cascade gotcha in `apps/desktop/src/lib/ipc/CLAUDE.md` § Type shape constraints. - Drop the misleading "wire format is camelCase" comment in `networking.ts`; re-export `UpgradeResult` from typed bindings instead of duplicating it. - Regen `bindings.ts`.
1 parent f122b7d commit 0d84e4e

13 files changed

Lines changed: 357 additions & 26 deletions

File tree

apps/desktop/src-tauri/src/file_system/listing/streaming.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::file_system::watcher::start_watching;
2424

2525
/// Status of a streaming directory listing
2626
#[derive(Debug, Clone, Serialize, Deserialize, specta::Type)]
27-
#[serde(rename_all = "camelCase", tag = "status")]
27+
#[serde(rename_all = "camelCase", rename_all_fields = "camelCase", tag = "status")]
2828
pub enum ListingStatus {
2929
Loading,
3030
Ready,

apps/desktop/src-tauri/src/file_system/validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub const MAX_PATH_BYTES: usize = 1024;
1818

1919
/// Validation error types for filename and path checks.
2020
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, specta::Type)]
21-
#[serde(rename_all = "camelCase", tag = "kind")]
21+
#[serde(rename_all = "camelCase", rename_all_fields = "camelCase", tag = "kind")]
2222
pub enum ValidationError {
2323
/// Name is empty or whitespace-only after trimming.
2424
Empty,

apps/desktop/src-tauri/src/licensing/verification.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use tauri_plugin_store::StoreExt;
1515
/// Serialized with `tag = "code"` so the frontend receives `{ code: "badSignature", ... }` and
1616
/// can switch on the code instead of pattern-matching English error strings.
1717
#[derive(Debug, Clone, Serialize, specta::Type)]
18-
#[serde(tag = "code", rename_all = "camelCase")]
18+
#[serde(tag = "code", rename_all = "camelCase", rename_all_fields = "camelCase")]
1919
pub enum LicenseActivationError {
2020
/// Key doesn't have the expected format (no dot separator, wrong structure).
2121
InvalidFormat,

apps/desktop/src-tauri/src/network/smb_upgrade.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::network::get_discovered_hosts;
99

1010
/// Result of an SMB volume upgrade attempt.
1111
#[derive(serde::Serialize, specta::Type)]
12-
#[serde(tag = "status", rename_all = "camelCase")]
12+
#[serde(tag = "status", rename_all = "camelCase", rename_all_fields = "camelCase")]
1313
pub enum UpgradeResult {
1414
/// Upgrade succeeded: volume now uses direct smb2.
1515
Success,

apps/desktop/src-tauri/src/stubs/mtp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub struct ConnectedDeviceInfo {
4040

4141
/// Error types for MTP connection operations (stub version).
4242
#[derive(Debug, Clone, Serialize, Deserialize, specta::Type)]
43-
#[serde(rename_all = "camelCase", tag = "type")]
43+
#[serde(rename_all = "camelCase", rename_all_fields = "camelCase", tag = "type")]
4444
pub enum MtpConnectionError {
4545
NotSupported { message: String },
4646
}

apps/desktop/src-tauri/src/stubs/network.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ pub async fn mount_network_share(
345345

346346
/// Result of an SMB volume upgrade attempt (stub version mirrors real type).
347347
#[derive(serde::Serialize, specta::Type)]
348-
#[serde(tag = "status", rename_all = "camelCase")]
348+
#[serde(tag = "status", rename_all = "camelCase", rename_all_fields = "camelCase")]
349349
pub enum UpgradeResult {
350350
NetworkError { message: String },
351351
}

apps/desktop/src/lib/ipc/CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,13 @@ Two patterns specta rc.24 can't handle. New code must avoid them; existing exclu
8181
type names in the TS output. Workaround: replace `Value` with a typed struct or enum. For genuinely free-form data
8282
where typing has no value, keep the call on raw `invoke()` with the standard opt-out comment (see § Excluded commands
8383
below). Try not to add new uses of `Value` at IPC boundaries.
84+
- **Internally-tagged enums with struct variants need `rename_all_fields`**: `#[serde(tag = "...", rename_all =
85+
"camelCase")]` renames variant *tags* but does not cascade into the variants' fields. A `display_name: String` field
86+
on a struct variant ships as `display_name` on the wire (and in `bindings.ts`), not `displayName`. Always pair the
87+
enum attribute with `rename_all_fields = "camelCase"` so field names follow the convention too. Symptom when missed:
88+
TS code reading `info.displayName` gets `undefined`; single-word fields (`share`, `port`) silently work, multi-word
89+
fields don't. There's a guardrail check (`scripts/check/checks/ipc-enum-camelcase.go`) that flags any
90+
`#[serde(tag = ..., rename_all = "camelCase")]` enum with struct variants that's missing `rename_all_fields`.
8491

8592
## Excluded commands
8693

apps/desktop/src/lib/ipc/bindings.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2961,9 +2961,9 @@ export type UpgradeResult =
29612961
share: string
29622962
port: number
29632963
// Friendly display name for the server (mDNS hostname or IP).
2964-
display_name: string
2964+
displayName: string
29652965
// Username hint from stored credentials or the OS mount.
2966-
username_hint: string | null
2966+
usernameHint: string | null
29672967
// Optional message explaining why credentials are needed.
29682968
message: string | null
29692969
}

apps/desktop/src/lib/tauri-commands/networking.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { listen, type UnlistenFn } from '@tauri-apps/api/event'
44
import { commands } from '$lib/ipc/bindings'
5-
import type { MountResult, SmbCredentials } from '$lib/ipc/bindings'
5+
import type { MountResult, SmbCredentials, UpgradeResult } from '$lib/ipc/bindings'
66
import { throwIpcError } from './ipc-types'
77
import type {
88
AuthOptions,
@@ -305,18 +305,7 @@ export async function mountNetworkShare(
305305
}
306306

307307
/** Result of an SMB volume upgrade attempt. */
308-
export type UpgradeResult =
309-
| { status: 'success' }
310-
| {
311-
status: 'credentialsNeeded'
312-
server: string
313-
share: string
314-
port: number
315-
displayName: string
316-
usernameHint: string | null
317-
message: string | null
318-
}
319-
| { status: 'networkError'; message: string }
308+
export type { UpgradeResult }
320309

321310
/**
322311
* Upgrades an existing OS-mounted SMB volume to use a direct smb2 connection.
@@ -327,8 +316,7 @@ export type UpgradeResult =
327316
export async function upgradeToSmbVolume(volumeId: string): Promise<UpgradeResult> {
328317
const res = await commands.upgradeToSmbVolume(volumeId)
329318
if (res.status === 'error') throwIpcError(res.error)
330-
// specta rc.24 emits snake_case for these enum fields; actual wire format is camelCase (serde rename_all).
331-
return res.data as unknown as UpgradeResult
319+
return res.data
332320
}
333321

334322
/**
@@ -342,8 +330,7 @@ export async function upgradeToSmbVolumeWithCredentials(
342330
): Promise<UpgradeResult> {
343331
const res = await commands.upgradeToSmbVolumeWithCredentials(volumeId, username, password, rememberInKeychain)
344332
if (res.status === 'error') throwIpcError(res.error)
345-
// specta rc.24 emits snake_case for these enum fields; actual wire format is camelCase (serde rename_all).
346-
return res.data as unknown as UpgradeResult
333+
return res.data
347334
}
348335

349336
/**

scripts/check/CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ before tests.
200200

201201
| App | Tech | Checks |
202202
| ---------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
203-
| Desktop | Rust | rustfmt, clippy, cargo-audit, cargo-deny, cargo-udeps, jscpd, log-error-macro, error-string-match, bindings-fresh, tests, integration-tests (Docker SMB), tests-linux (slow) |
203+
| Desktop | Rust | rustfmt, clippy, cargo-audit, cargo-deny, cargo-udeps, jscpd, log-error-macro, error-string-match, bindings-fresh, ipc-enum-camelcase, tests, integration-tests (Docker SMB), tests-linux (slow) |
204204
| Desktop | Svelte | prettier, eslint, eslint-typecheck (slow), stylelint, css-unused, a11y-contrast, svelte-check, import-cycles, knip, type-drift, tests, e2e-linux-typecheck, e2e-linux (slow), e2e-playwright (slow) |
205205
| Website | Astro | prettier, eslint, typecheck, build, html-validate, e2e |
206206
| Website | Docker | docker-build |

0 commit comments

Comments
 (0)