fix: standardize punctuation
This commit is contained in:
@@ -61,7 +61,7 @@ export const useAccountStore = create<AccountState>()(
|
||||
|
||||
const id = generateAccountId(entry.username, entry.serverUrl);
|
||||
if (state.accounts.some((a) => a.id === id)) {
|
||||
// Already exists — update mutable fields and return existing id
|
||||
// Already exists - update mutable fields and return existing id
|
||||
set((s) => ({
|
||||
accounts: s.accounts.map((a) =>
|
||||
a.id === id
|
||||
|
||||
+11
-11
@@ -430,7 +430,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
if (!upgradedToOAuth) {
|
||||
const { useTotpReauthStore } = await import('@/stores/totp-reauth-store');
|
||||
client.enableTotpReauth(password, () => useTotpReauthStore.getState().requestTotp());
|
||||
debug.log('auth', 'TOTP re-auth enabled — user will be prompted for fresh codes on session expiry');
|
||||
debug.log('auth', 'TOTP re-auth enabled - user will be prompted for fresh codes on session expiry');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -920,7 +920,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
const remainingAccounts = accountStore.accounts;
|
||||
|
||||
if (remainingAccounts.length > 0 && !wasDemoMode) {
|
||||
// Switch to the next account — this is the one path that stays in-app
|
||||
// Switch to the next account - this is the one path that stays in-app
|
||||
const nextAccount = remainingAccounts[0];
|
||||
clearAllStores();
|
||||
|
||||
@@ -955,7 +955,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
}).catch((err) => debug.error('Failed to load identities after switch:', err));
|
||||
}
|
||||
} else {
|
||||
// Client not in memory — clear everything and redirect.
|
||||
// Client not in memory - clear everything and redirect.
|
||||
// Trying to async-restore during logout caused the original bug.
|
||||
debug.error(`Cannot restore next account ${nextAccount.id}, performing full logout`);
|
||||
evictAccount(nextAccount.id);
|
||||
@@ -971,12 +971,12 @@ export const useAuthStore = create<AuthState>()(
|
||||
return;
|
||||
}
|
||||
|
||||
// No accounts remaining (or demo mode) — full logout + redirect
|
||||
// No accounts remaining (or demo mode) - full logout + redirect
|
||||
performFullLogout(set);
|
||||
|
||||
notifyParent('sso:logout');
|
||||
|
||||
// Background cookie/token cleanup — keepalive ensures completion during navigation
|
||||
// Background cookie/token cleanup - keepalive ensures completion during navigation
|
||||
if (!wasDemoMode) {
|
||||
apiFetch(`/api/auth/session?slot=${slot}`, { method: 'DELETE', keepalive: true }).catch(() => {});
|
||||
if (wasOAuth) {
|
||||
@@ -984,7 +984,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to login — this is synchronous and happens AFTER all state is cleared
|
||||
// Redirect to login - this is synchronous and happens AFTER all state is cleared
|
||||
redirectToLogin();
|
||||
},
|
||||
|
||||
@@ -1039,7 +1039,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
let targetRestoreRateLimited = false;
|
||||
|
||||
if (!targetClient) {
|
||||
// Client not connected — try to restore
|
||||
// Client not connected - try to restore
|
||||
try {
|
||||
if (targetAccount.authMode === 'oauth') {
|
||||
const res = await apiFetch(`/api/auth/token?slot=${targetAccount.cookieSlot}`, { method: 'PUT' });
|
||||
@@ -1105,7 +1105,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
return;
|
||||
}
|
||||
|
||||
// Cannot restore — remove the stale account and redirect to login
|
||||
// Cannot restore - remove the stale account and redirect to login
|
||||
evictAccount(accountId);
|
||||
accountStore.removeAccount(accountId);
|
||||
apiFetch(`/api/auth/session?slot=${targetAccount.cookieSlot}`, { method: 'DELETE' }).catch(() => {});
|
||||
@@ -1239,7 +1239,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
throw new Error(`Session cookie missing: ${res.status}`);
|
||||
}
|
||||
} else {
|
||||
// Basic auth without rememberMe — can't restore
|
||||
// Basic auth without rememberMe - can't restore
|
||||
throw new Error('No saved session');
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -1523,7 +1523,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
const { identities, primaryIdentity } = loadIdentities(rawIdentities, username);
|
||||
set({ identities, primaryIdentity });
|
||||
} catch {
|
||||
// Silently fail — background sync should not surface errors to the user
|
||||
// Silently fail - background sync should not surface errors to the user
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1538,7 +1538,7 @@ export const useAuthStore = create<AuthState>()(
|
||||
{
|
||||
name: 'auth-storage',
|
||||
partialize: (state) => {
|
||||
// Don't persist unauthenticated state — prevents resurrecting stale sessions
|
||||
// Don't persist unauthenticated state - prevents resurrecting stale sessions
|
||||
if (!state.isAuthenticated) return {};
|
||||
return {
|
||||
serverUrl: state.serverUrl,
|
||||
|
||||
@@ -374,7 +374,7 @@ export const useCalendarStore = create<CalendarStore>()(
|
||||
|
||||
rsvpEvent: async (client, eventId, participantId, status, replyTo) => {
|
||||
set({ error: null });
|
||||
// JMAP participant IDs are opaque strings — they can contain @, ., :, / etc.
|
||||
// JMAP participant IDs are opaque strings - they can contain @, ., :, / etc.
|
||||
// Only reject empty or obviously malicious values (path traversal).
|
||||
if (!participantId || participantId.includes('..')) {
|
||||
set({ error: 'Invalid participant ID' });
|
||||
@@ -448,15 +448,15 @@ export const useCalendarStore = create<CalendarStore>()(
|
||||
|
||||
for (const e of eventsToProcess) {
|
||||
if (!e.uid || !uidToEvent.has(e.uid)) {
|
||||
// UID doesn't exist on server — create it
|
||||
// UID doesn't exist on server - create it
|
||||
newEvents.push(e);
|
||||
} else {
|
||||
const existing = uidToEvent.get(e.uid)!;
|
||||
if (existing.calendarIds[realCalendarId]) {
|
||||
// Already in target calendar — skip
|
||||
// Already in target calendar - skip
|
||||
continue;
|
||||
}
|
||||
// Exists in another calendar — link to target calendar
|
||||
// Exists in another calendar - link to target calendar
|
||||
eventsToLink.push({
|
||||
eventId: existing.id,
|
||||
calendarIds: { ...existing.calendarIds, [realCalendarId]: true },
|
||||
|
||||
@@ -14,7 +14,7 @@ export function getContactDisplayName(contact: ContactCard): string {
|
||||
const full = [given, surname].filter(Boolean).join(' ');
|
||||
if (full) return full;
|
||||
}
|
||||
// Fall back to name.full (RFC 9553 — used by Stalwart and other JMAP servers)
|
||||
// Fall back to name.full (RFC 9553 - used by Stalwart and other JMAP servers)
|
||||
if (contact.name.full) return contact.name.full;
|
||||
}
|
||||
if (contact.nicknames) {
|
||||
|
||||
@@ -1089,7 +1089,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
||||
return mb.accountId === acctId;
|
||||
});
|
||||
if (!trashMailbox) {
|
||||
// No trash available for this account — fall back to destroy so the action isn't silently dropped.
|
||||
// No trash available for this account - fall back to destroy so the action isn't silently dropped.
|
||||
await acctClient.batchDeleteEmails(ids);
|
||||
return;
|
||||
}
|
||||
@@ -1732,7 +1732,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
||||
receivedAt: new Date(Date.now() - 3600000).toISOString(),
|
||||
from: [{ name: "Emily Chen", email: "emily.chen@gmail.com" }],
|
||||
to: [{ email: "you@example.com" }],
|
||||
subject: "Re: Dashboard Redesign v2 — feedback",
|
||||
subject: "Re: Dashboard Redesign v2 - feedback",
|
||||
preview: "Hey! I just pushed the updated mockups to Figma. I incorporated all the feedback from last week's meeting. Let me know what you think about the new nav...",
|
||||
hasAttachment: true,
|
||||
},
|
||||
@@ -1784,7 +1784,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
||||
receivedAt: new Date(Date.now() - 108000000).toISOString(),
|
||||
from: [{ name: "Sarah Kim", email: "sarah.kim@proton.me" }],
|
||||
to: [{ email: "you@example.com" }],
|
||||
subject: "Conference talk proposal — need your review",
|
||||
subject: "Conference talk proposal - need your review",
|
||||
preview: "I'm submitting a talk to ReactConf about our email client architecture. Could you take a look at my abstract before the deadline on Friday?...",
|
||||
hasAttachment: true,
|
||||
},
|
||||
|
||||
@@ -224,7 +224,7 @@ export const useFileStore = create<FileState>((set, get) => ({
|
||||
try { localStorage.setItem('files-path-stack', JSON.stringify(newStack)); } catch { /* ignore */ }
|
||||
|
||||
try {
|
||||
// Always fetch all nodes from root — Stalwart doesn't support parentId nesting
|
||||
// Always fetch all nodes from root - Stalwart doesn't support parentId nesting
|
||||
const allNodes = await client.listFileNodes(null);
|
||||
const prefix = getPathPrefix(newPath);
|
||||
const filteredNodes = filterNodesByPrefix(allNodes, prefix);
|
||||
@@ -389,7 +389,7 @@ export const useFileStore = create<FileState>((set, get) => ({
|
||||
try {
|
||||
await client.createFileDirectory(fullDirName, null);
|
||||
} catch {
|
||||
// Directory may already exist — ignore
|
||||
// Directory may already exist - ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ export const useFilterStore = create<FilterStore>()((set, get) => ({
|
||||
const allScripts = await client.getSieveScripts();
|
||||
debug.log('filters', 'Sieve scripts fetched:', allScripts.length);
|
||||
|
||||
// Skip the server-managed 'vacation' script (RFC 9661 §4) — it can only
|
||||
// Skip the server-managed 'vacation' script (RFC 9661 §4) - it can only
|
||||
// be modified via VacationResponse/set, not SieveScript/set.
|
||||
const scripts = allScripts.filter(s => s.name !== 'vacation');
|
||||
|
||||
@@ -224,7 +224,7 @@ export const useFilterStore = create<FilterStore>()((set, get) => ({
|
||||
const content = generateScript(rules, vacation.isEnabled ? vacation : undefined, { externalRequires });
|
||||
|
||||
if (activeScript) {
|
||||
// Preserve the script's current activation state — don't pass activate: true
|
||||
// Preserve the script's current activation state - don't pass activate: true
|
||||
// unconditionally, as that would deactivate the server-managed 'vacation'
|
||||
// script and cause VacationResponse/get to return isEnabled: false.
|
||||
await client.updateSieveScript(activeScript.id, content, activeScript.isActive);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Plugin store — manages installed plugins, slot registrations, and lifecycle
|
||||
// Plugin store - manages installed plugins, slot registrations, and lifecycle
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
@@ -274,7 +274,7 @@ export const usePluginStore = create<PluginStoreState>()(
|
||||
status: p.enabled ? 'enabled' : 'installed',
|
||||
error: undefined,
|
||||
})),
|
||||
// Don't persist slots — they are runtime-only, rebuilt on load
|
||||
// Don't persist slots - they are runtime-only, rebuilt on load
|
||||
}),
|
||||
onRehydrateStorage: () => {
|
||||
return (state) => {
|
||||
@@ -381,7 +381,7 @@ async function syncServerPlugins(
|
||||
const local = get().plugins.find(p => p.id === sp.id);
|
||||
|
||||
if (!local) {
|
||||
// New server plugin — download and install
|
||||
// New server plugin - download and install
|
||||
const code = await downloadPluginBundle(sp.id);
|
||||
if (!code) continue;
|
||||
|
||||
@@ -411,7 +411,7 @@ async function syncServerPlugins(
|
||||
return { plugins: [...state.plugins, plugin] };
|
||||
});
|
||||
} else if (local.version !== sp.version) {
|
||||
// Version changed — re-download bundle
|
||||
// Version changed - re-download bundle
|
||||
const code = await downloadPluginBundle(sp.id);
|
||||
if (!code) continue;
|
||||
|
||||
@@ -478,7 +478,7 @@ async function syncServerPlugins(
|
||||
// Persist current server plugin IDs for future cleanup
|
||||
setServerManagedPluginIds(serverPluginIds);
|
||||
} catch {
|
||||
// Sync failure is non-fatal — client continues with local plugins
|
||||
// Sync failure is non-fatal - client continues with local plugins
|
||||
console.warn('[plugin-store] Server plugin sync failed, using local plugins only');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ interface SmimeStore extends SmimePersistedState {
|
||||
// Loaded from IndexedDB
|
||||
keyRecords: SmimeKeyRecord[];
|
||||
publicCerts: SmimePublicCert[];
|
||||
// Runtime only — never persisted
|
||||
// Runtime only - never persisted
|
||||
unlockedKeys: Map<string, CryptoKey>;
|
||||
unlockedDecryptionKeys: Map<string, CryptoKey>;
|
||||
unlockedLegacyDecryptionKeys: Map<string, CryptoKey>;
|
||||
@@ -282,7 +282,7 @@ export const useSmimeStore = create<SmimeStore>()(
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const cert = parseCertificatePemOrDer(data);
|
||||
// Always re-encode to DER — input might be PEM text (string or ArrayBuffer)
|
||||
// Always re-encode to DER - input might be PEM text (string or ArrayBuffer)
|
||||
const der = cert.toSchema(true).toBER(false);
|
||||
const info = await extractCertificateInfo(cert, der);
|
||||
const email = info.emailAddresses[0] ?? '';
|
||||
|
||||
Reference in New Issue
Block a user