style: trim narration comments from recent changes

This commit is contained in:
2026-08-23 20:06:05 -07:00
parent c342b91029
commit 58702da156
16 changed files with 21 additions and 75 deletions
-2
View File
@@ -140,8 +140,6 @@ export const Route = createRootRouteWithContext<{
); );
const locale = resolveLocale(auth?.metadata?.locale); const locale = resolveLocale(auth?.metadata?.locale);
await ensureMessages(locale); await ensureMessages(locale);
// Dehydrate the catalog with the page so the client hydrates in the
// active locale instead of falling back to en until a chunk loads.
if (typeof window === "undefined" && locale !== DEFAULT_LOCALE) { if (typeof window === "undefined" && locale !== DEFAULT_LOCALE) {
context.queryClient.setQueryData( context.queryClient.setQueryData(
i18nMessagesQueryKey(locale), i18nMessagesQueryKey(locale),
-3
View File
@@ -5,7 +5,6 @@ import { Trans, useLingui } from '@lingui/react/macro'
import { useAuth } from '@/contexts/auth-context' import { useAuth } from '@/contexts/auth-context'
import { useIsMobile } from '@/hooks/use-is-mobile' import { useIsMobile } from '@/hooks/use-is-mobile'
// Navbar geometry: 4rem height + 0.5rem margin + its safe-area bottom offset.
const ABOVE_MOBILE_NAV_OFFSET = 'calc(4.5rem + env(safe-area-inset-bottom, 0px))' const ABOVE_MOBILE_NAV_OFFSET = 'calc(4.5rem + env(safe-area-inset-bottom, 0px))'
export function IOSInstallPrompt() { export function IOSInstallPrompt() {
@@ -43,8 +42,6 @@ export function IOSInstallPrompt() {
? t`Tap Share → Add to Home Screen` ? t`Tap Share → Add to Home Screen`
: t`Tap Menu (⋮) → Add to Home screen` : t`Tap Menu (⋮) → Add to Home screen`
// Navbar renders only under _authed, so a signed-in mobile user on a public
// route has no nav to clear.
const aboveBottomNav = Boolean(user) && isMobile const aboveBottomNav = Boolean(user) && isMobile
const bottomStyle = aboveBottomNav const bottomStyle = aboveBottomNav
? { bottom: ABOVE_MOBILE_NAV_OFFSET, paddingBottom: '8px' } ? { bottom: ABOVE_MOBILE_NAV_OFFSET, paddingBottom: '8px' }
@@ -5,9 +5,6 @@ const eventListerOptions = {
}; };
const useVisualViewportSize = () => { const useVisualViewportSize = () => {
// Starts at zero on server and client alike, filling in after mount — the
// same contract as Mantine's useViewportSize. Reading window during render
// makes the client's first render disagree with the SSR markup.
const [windowSize, setWindowSize] = useState({ const [windowSize, setWindowSize] = useState({
width: 0, width: 0,
height: 0, height: 0,
-3
View File
@@ -41,7 +41,6 @@ export async function ensureMessages(locale: AppLocale): Promise<Messages> {
const loader = catalogLoaders[`/src/locales/${locale}/messages.po`]; const loader = catalogLoaders[`/src/locales/${locale}/messages.po`];
if (!loader) return messageCache[DEFAULT_LOCALE]!; if (!loader) return messageCache[DEFAULT_LOCALE]!;
// Dedupe concurrent loads; a rejected load is dropped so a retry can succeed.
const pending = (inflightLoads[locale] ??= loader() const pending = (inflightLoads[locale] ??= loader()
.then(({ messages }) => { .then(({ messages }) => {
messageCache[locale] = messages; messageCache[locale] = messages;
@@ -57,8 +56,6 @@ export function primeMessages(locale: AppLocale, messages: Messages) {
messageCache[locale] ??= messages; messageCache[locale] ??= messages;
} }
// Seeded into the SSR-dehydrated query cache so hydration renders the active
// locale without depending on a client-side catalog chunk load.
export const i18nMessagesQueryKey = (locale: AppLocale) => export const i18nMessagesQueryKey = (locale: AppLocale) =>
["i18n-messages", locale] as const; ["i18n-messages", locale] as const;
-7
View File
@@ -36,11 +36,6 @@ export const LinguiProvider = ({ children }: { children: React.ReactNode }) => {
const locale = resolveLocale(data?.metadata?.locale); const locale = resolveLocale(data?.metadata?.locale);
const [catalogVersion, setCatalogVersion] = useState(0); const [catalogVersion, setCatalogVersion] = useState(0);
// Fresh instance per locale (and per SSR request tree). __root beforeLoad
// dehydrates the active locale's catalog with the page, so hydration primes
// it from the query cache and never regresses to en for the SSR'd locale.
// Public routes (login) may still lack it — createI18n falls back to en
// until the effect below loads it and bumps catalogVersion.
const i18n = useMemo( const i18n = useMemo(
() => { () => {
if (!hasCachedMessages(locale)) { if (!hasCachedMessages(locale)) {
@@ -59,8 +54,6 @@ export const LinguiProvider = ({ children }: { children: React.ReactNode }) => {
if (hasCachedMessages(locale)) return; if (hasCachedMessages(locale)) return;
let cancelled = false; let cancelled = false;
let retryTimer: ReturnType<typeof setTimeout> | undefined; let retryTimer: ReturnType<typeof setTimeout> | undefined;
// A failed chunk load must not strand the UI in en — retry until the
// catalog arrives or the locale changes.
const load = () => { const load = () => {
ensureMessages(locale).then( ensureMessages(locale).then(
() => { () => {
+2 -10
View File
@@ -19,17 +19,13 @@ class PocketBaseAdminClient {
this.pb = new PocketBase(process.env.POCKETBASE_URL); this.pb = new PocketBase(process.env.POCKETBASE_URL);
this.pb.beforeSend = async (url, options) => { this.pb.beforeSend = async (url, options) => {
// The auth requests themselves must skip the gate below: gating them on // Auth requests skip the gate: awaiting authPromise here would deadlock them.
// authPromise would make them await their own completion (deadlock).
if (!url.includes("/collections/_superusers/auth-")) { if (!url.includes("/collections/_superusers/auth-")) {
try { try {
await this.authPromise; await this.authPromise;
} catch { } catch {}
// Swallow: fall through to self-heal so a rejected authPromise can't strand every request.
}
if (!this.pb.authStore.isValid) { if (!this.pb.authStore.isValid) {
// Self-heal: re-auth once PocketBase is reachable again, no restart.
this.authPromise = this.authenticate(); this.authPromise = this.authenticate();
await this.authPromise; await this.authPromise;
this.startTokenRefresh(); this.startTokenRefresh();
@@ -43,8 +39,6 @@ class PocketBaseAdminClient {
} }
} }
// The SDK stamps Authorization before this hook runs, so a request
// built while auth was still in flight carries no (or a stale) token.
options.headers = { options.headers = {
...options.headers, ...options.headers,
Authorization: this.pb.authStore.token, Authorization: this.pb.authStore.token,
@@ -75,8 +69,6 @@ class PocketBaseAdminClient {
Object.assign(this, createPushService(this.pb)); Object.assign(this, createPushService(this.pb));
this.authPromise = this.authenticate(); this.authPromise = this.authenticate();
// Fail soft at boot: an unreachable PocketBase must not crash the process;
// beforeSend self-heals on the next request.
this.authPromise this.authPromise
.then(() => { .then(() => {
this.startTokenRefresh(); this.startTokenRefresh();
+1 -9
View File
@@ -2,17 +2,9 @@ import type PocketBase from "pocketbase";
export type FilterParam = string | number | boolean | Date | null; export type FilterParam = string | number | boolean | Date | null;
// Any key the SDK's own `replaceAll("{:" + key + "}", …)` loop would substitute,
// so which keys resolve does not depend on the characters they are spelled with.
const PLACEHOLDER = /\{:([^}]+)\}/g; const PLACEHOLDER = /\{:([^}]+)\}/g;
// `pb.filter` substitutes with String.replaceAll and a *string* replacement, so // pb.filter $-expands string replacements; doubling `$` keeps the value literal.
// `$&`, `` $` ``, `$'` and `$$` inside a value are expanded as replacement
// patterns: the value's own text, or a slice of the surrounding expression,
// gets spliced into the quoted literal. Doubling every `$` first collapses back
// to the exact literal inside that same replaceAll. The FilterParam union is
// load-bearing — it keeps objects and arrays out of the SDK's JSON.stringify
// branch, which would reintroduce an undoubled `$`.
const quote = (pb: PocketBase, value: FilterParam) => const quote = (pb: PocketBase, value: FilterParam) =>
pb.filter("{:v}", { pb.filter("{:v}", {
v: typeof value === "string" ? value.replaceAll("$", () => "$$") : value, v: typeof value === "string" ? value.replaceAll("$", () => "$$") : value,
+1 -8
View File
@@ -1,10 +1,3 @@
// `pb.filter()` escapes single quotes and nothing else, so a term ending in a // Escapes LIKE metacharacters and wraps in `%` for a literal substring match.
// backslash escapes the closing quote of the literal it is substituted into and
// PocketBase rejects the whole expression with 400 validation_invalid_filter.
// Escaping `\ % _` and appending the wildcards here keeps the operand's last
// character a literal `%`, and makes `~` an unconditional substring match:
// PocketBase only auto-wraps (and only auto-escapes) operands that contain no
// `%` of their own, so a term carrying one would otherwise silently become a
// prefix match, and a bare `_` would match every row.
export const likePattern = (term: string) => export const likePattern = (term: string) =>
`%${term.replace(/[\\%_]/g, (char) => `\\${char}`)}%`; `%${term.replace(/[\\%_]/g, (char) => `\\${char}`)}%`;
-3
View File
@@ -1,13 +1,10 @@
// Shared redaction for logs + audit rows so the two never drift.
export const SENSITIVE_KEY = /token|secret|password|phone|otp|code|auth|key/i; export const SENSITIVE_KEY = /token|secret|password|phone|otp|code|auth|key/i;
const REDACTED = "[redacted]"; const REDACTED = "[redacted]";
// Deep-redact: keys matching SENSITIVE_KEY become "[redacted]"; primitives pass through.
export const redactValue = (value: unknown): unknown => { export const redactValue = (value: unknown): unknown => {
if (Array.isArray(value)) return value.map(redactValue); if (Array.isArray(value)) return value.map(redactValue);
if (value && typeof value === "object") { if (value && typeof value === "object") {
// Keep Error serializable.
if (value instanceof Error) { if (value instanceof Error) {
return { name: value.name, message: value.message, stack: value.stack }; return { name: value.name, message: value.message, stack: value.stack };
} }
@@ -16,8 +16,6 @@ export const createServerError = (
context, context,
}); });
// Audit rows are written by serverFnLoggingMiddleware, which reads the
// returned envelope's success flag — never write them here.
export const toServerResult = async <T>( export const toServerResult = async <T>(
serverFn: () => Promise<T> serverFn: () => Promise<T>
): Promise<ServerResult<T>> => { ): Promise<ServerResult<T>> => {
+4 -4
View File
@@ -392,7 +392,7 @@ msgstr "Aktivitäten"
msgid "Activity Details" msgid "Activity Details"
msgstr "Aktivitätsdetails" msgstr "Aktivitätsdetails"
#: src/components/ios-install-prompt.tsx:61 #: src/components/ios-install-prompt.tsx:58
msgid "Add FLXN to your home screen for a smoother experience" msgid "Add FLXN to your home screen for a smoother experience"
msgstr "Leg FLXN auf deinen Homescreen für ein flüssigeres Erlebnis" msgstr "Leg FLXN auf deinen Homescreen für ein flüssigeres Erlebnis"
@@ -845,7 +845,7 @@ msgstr "deviceId ist für die Übertragungsaktion erforderlich"
msgid "Disconnect Spotify" msgid "Disconnect Spotify"
msgstr "Spotify trennen" msgstr "Spotify trennen"
#: src/components/ios-install-prompt.tsx:68 #: src/components/ios-install-prompt.tsx:65
msgid "Dismiss" msgid "Dismiss"
msgstr "Schließen" msgstr "Schließen"
@@ -2324,11 +2324,11 @@ msgstr "T"
msgid "Tap an opponent below to compare" msgid "Tap an opponent below to compare"
msgstr "Tippe unten auf einen Gegner zum Vergleichen" msgstr "Tippe unten auf einen Gegner zum Vergleichen"
#: src/components/ios-install-prompt.tsx:44 #: src/components/ios-install-prompt.tsx:43
msgid "Tap Menu (⋮) → Add to Home screen" msgid "Tap Menu (⋮) → Add to Home screen"
msgstr "Tippe auf Menü (⋮) → Zum Home-Bildschirm hinzufügen" msgstr "Tippe auf Menü (⋮) → Zum Home-Bildschirm hinzufügen"
#: src/components/ios-install-prompt.tsx:43 #: src/components/ios-install-prompt.tsx:42
msgid "Tap Share → Add to Home Screen" msgid "Tap Share → Add to Home Screen"
msgstr "Tippe auf Teilen → Zum Home-Bildschirm hinzufügen" msgstr "Tippe auf Teilen → Zum Home-Bildschirm hinzufügen"
+4 -4
View File
@@ -392,7 +392,7 @@ msgstr "Activities"
msgid "Activity Details" msgid "Activity Details"
msgstr "Activity Details" msgstr "Activity Details"
#: src/components/ios-install-prompt.tsx:61 #: src/components/ios-install-prompt.tsx:58
msgid "Add FLXN to your home screen for a smoother experience" msgid "Add FLXN to your home screen for a smoother experience"
msgstr "Add FLXN to your home screen for a smoother experience" msgstr "Add FLXN to your home screen for a smoother experience"
@@ -845,7 +845,7 @@ msgstr "deviceId is required for transfer action"
msgid "Disconnect Spotify" msgid "Disconnect Spotify"
msgstr "Disconnect Spotify" msgstr "Disconnect Spotify"
#: src/components/ios-install-prompt.tsx:68 #: src/components/ios-install-prompt.tsx:65
msgid "Dismiss" msgid "Dismiss"
msgstr "Dismiss" msgstr "Dismiss"
@@ -2324,11 +2324,11 @@ msgstr "T"
msgid "Tap an opponent below to compare" msgid "Tap an opponent below to compare"
msgstr "Tap an opponent below to compare" msgstr "Tap an opponent below to compare"
#: src/components/ios-install-prompt.tsx:44 #: src/components/ios-install-prompt.tsx:43
msgid "Tap Menu (⋮) → Add to Home screen" msgid "Tap Menu (⋮) → Add to Home screen"
msgstr "Tap Menu (⋮) → Add to Home screen" msgstr "Tap Menu (⋮) → Add to Home screen"
#: src/components/ios-install-prompt.tsx:43 #: src/components/ios-install-prompt.tsx:42
msgid "Tap Share → Add to Home Screen" msgid "Tap Share → Add to Home Screen"
msgstr "Tap Share → Add to Home Screen" msgstr "Tap Share → Add to Home Screen"
+4 -4
View File
@@ -392,7 +392,7 @@ msgstr "Actividades"
msgid "Activity Details" msgid "Activity Details"
msgstr "Detalles de la actividad" msgstr "Detalles de la actividad"
#: src/components/ios-install-prompt.tsx:61 #: src/components/ios-install-prompt.tsx:58
msgid "Add FLXN to your home screen for a smoother experience" msgid "Add FLXN to your home screen for a smoother experience"
msgstr "Agrega FLXN a tu pantalla de inicio para una experiencia más fluida" msgstr "Agrega FLXN a tu pantalla de inicio para una experiencia más fluida"
@@ -845,7 +845,7 @@ msgstr "Se requiere deviceId para la acción de transferencia"
msgid "Disconnect Spotify" msgid "Disconnect Spotify"
msgstr "Desconectar Spotify" msgstr "Desconectar Spotify"
#: src/components/ios-install-prompt.tsx:68 #: src/components/ios-install-prompt.tsx:65
msgid "Dismiss" msgid "Dismiss"
msgstr "Cerrar" msgstr "Cerrar"
@@ -2324,11 +2324,11 @@ msgstr "T"
msgid "Tap an opponent below to compare" msgid "Tap an opponent below to compare"
msgstr "Toca un oponente abajo para comparar" msgstr "Toca un oponente abajo para comparar"
#: src/components/ios-install-prompt.tsx:44 #: src/components/ios-install-prompt.tsx:43
msgid "Tap Menu (⋮) → Add to Home screen" msgid "Tap Menu (⋮) → Add to Home screen"
msgstr "Toca Menú (⋮) → Agregar a pantalla de inicio" msgstr "Toca Menú (⋮) → Agregar a pantalla de inicio"
#: src/components/ios-install-prompt.tsx:43 #: src/components/ios-install-prompt.tsx:42
msgid "Tap Share → Add to Home Screen" msgid "Tap Share → Add to Home Screen"
msgstr "Toca Compartir → Agregar a pantalla de inicio" msgstr "Toca Compartir → Agregar a pantalla de inicio"
+4 -4
View File
@@ -392,7 +392,7 @@ msgstr "アクティビティ"
msgid "Activity Details" msgid "Activity Details"
msgstr "アクティビティの詳細" msgstr "アクティビティの詳細"
#: src/components/ios-install-prompt.tsx:61 #: src/components/ios-install-prompt.tsx:58
msgid "Add FLXN to your home screen for a smoother experience" msgid "Add FLXN to your home screen for a smoother experience"
msgstr "FLXNをホーム画面に追加すると、もっと快適に使えます" msgstr "FLXNをホーム画面に追加すると、もっと快適に使えます"
@@ -845,7 +845,7 @@ msgstr "転送操作にはdeviceIdが必要です"
msgid "Disconnect Spotify" msgid "Disconnect Spotify"
msgstr "Spotifyの連携を解除" msgstr "Spotifyの連携を解除"
#: src/components/ios-install-prompt.tsx:68 #: src/components/ios-install-prompt.tsx:65
msgid "Dismiss" msgid "Dismiss"
msgstr "閉じる" msgstr "閉じる"
@@ -2324,11 +2324,11 @@ msgstr "T"
msgid "Tap an opponent below to compare" msgid "Tap an opponent below to compare"
msgstr "下の対戦相手をタップして比較" msgstr "下の対戦相手をタップして比較"
#: src/components/ios-install-prompt.tsx:44 #: src/components/ios-install-prompt.tsx:43
msgid "Tap Menu (⋮) → Add to Home screen" msgid "Tap Menu (⋮) → Add to Home screen"
msgstr "メニュー (⋮) をタップ →「ホーム画面に追加」" msgstr "メニュー (⋮) をタップ →「ホーム画面に追加」"
#: src/components/ios-install-prompt.tsx:43 #: src/components/ios-install-prompt.tsx:42
msgid "Tap Share → Add to Home Screen" msgid "Tap Share → Add to Home Screen"
msgstr "共有をタップ →「ホーム画面に追加」" msgstr "共有をタップ →「ホーム画面に追加」"
+1 -8
View File
@@ -41,19 +41,13 @@ type Actor = { player_id?: string };
type ServerFnMeta = { name?: string }; type ServerFnMeta = { name?: string };
// Start's default generateFunctionId hashes the entry id, so the URL segment is // The URL segment is a hash of the fn id; serverFnMeta carries the readable name.
// a sha256 and the compile-time meta is the only readable name. The path stays
// as the fallback for requests that carry no meta.
const serverFnName = (request: Request, meta?: ServerFnMeta): string => { const serverFnName = (request: Request, meta?: ServerFnMeta): string => {
if (meta?.name) return meta.name; if (meta?.name) return meta.name;
const pathParts = new URL(request.url).pathname.split("/").filter(Boolean); const pathParts = new URL(request.url).pathname.split("/").filter(Boolean);
return pathParts[pathParts.length - 1] || "unknown"; return pathParts[pathParts.length - 1] || "unknown";
}; };
// The admin middleware refuses before serverFnLoggingMiddleware ever runs, so
// a denial has to write its own row — otherwise an operator reviewing the log
// during a probing attempt sees a clean history. The rejected payload is left
// out: it never reached a validator, so it is unbounded attacker input.
export const recordDeniedServerFn = ( export const recordDeniedServerFn = (
request: Request, request: Request,
actor?: Actor, actor?: Actor,
@@ -85,7 +79,6 @@ export const serverFnLoggingMiddleware = createMiddleware({
const result = await next(); const result = await next();
const duration = Date.now() - startTime; const duration = Date.now() - startTime;
// Single audit writer; toServerResult resolves { success:false } instead of throwing, so read the flag.
const envelope = (result as { result?: unknown })?.result; const envelope = (result as { result?: unknown })?.result;
const failed = const failed =
!!envelope && !!envelope &&
-1
View File
@@ -62,7 +62,6 @@ export const superTokensAdminFunctionMiddleware = createMiddleware({
return next({ context }); return next({ context });
} }
// Identifiers only — the full context carries phone + metadata.
logger.error("Unauthorized user in admin function.", { logger.error("Unauthorized user in admin function.", {
userAuthId: context.userAuthId, userAuthId: context.userAuthId,
roles: context.roles, roles: context.roles,