Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions src/decl/locale_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5461,6 +5461,7 @@ export type LocaleData = {
toast_title: string
error: {
load_failed: string
unlock_failed: string
}
achievements: {
open_achievements_page: {
Expand Down Expand Up @@ -5762,6 +5763,7 @@ export type LocaleKey = Paths<LocaleData>
*/
export type LocaleKeyParams = {
'achievements.error.load_failed': { message: string | number }
'achievements.error.unlock_failed': { error: string | number }
'achievements.unlocked_on': { date: string | number }
'auth.error.accountLockedRetry': { timeLeft: string | number }
'badges_maker.copy_error': { error: string | number }
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/ar-SA.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "غير مقفلة",
"toast_title": "الإنجازات مقفلة!",
"error": {
"load_failed": "فشل تحميل الإنجازات: ${message}"
"load_failed": "فشل تحميل الإنجازات: ${message}",
"unlock_failed": "فشل فتح الإنجاز: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Nicht entsperrt",
"toast_title": "Erfolge freigeschaltet!",
"error": {
"load_failed": "Erfolge konnten nicht geladen werden: ${message}"
"load_failed": "Erfolge konnten nicht geladen werden: ${message}",
"unlock_failed": "Erfolg konnte nicht freigeschaltet werden: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/emoji.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "🔒",
"toast_title": "🎉🏆❗",
"error": {
"load_failed": "🏆❌: ${message}"
"load_failed": "🏆❌: ${message}",
"unlock_failed": "🔓❌: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/en-UK.json
Original file line number Diff line number Diff line change
Expand Up @@ -5477,7 +5477,8 @@
"locked": "Not unlocked",
"toast_title": "Achievements unlocked!",
"error": {
"load_failed": "Failed to load achievements: ${message}"
"load_failed": "Failed to load achievements: ${message}",
"unlock_failed": "Failed to unlock achievement: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/es-ES.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "No desbloqueado",
"toast_title": "¡Logros desbloqueados!",
"error": {
"load_failed": "No se pudieron cargar los logros: ${message}"
"load_failed": "No se pudieron cargar los logros: ${message}",
"unlock_failed": "No se pudo desbloquear el logro: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Non débloqué",
"toast_title": "Succès débloqués !",
"error": {
"load_failed": "Échec du chargement des succès : ${message}"
"load_failed": "Échec du chargement des succès : ${message}",
"unlock_failed": "Échec du déblocage du succès : ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/hi-IN.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "अनलॉक नहीं किया गया",
"toast_title": "उपलब्धियाँ खुलीं!",
"error": {
"load_failed": "उपलब्धियाँ लोड करने में विफल: ${message}"
"load_failed": "उपलब्धियाँ लोड करने में विफल: ${message}",
"unlock_failed": "उपलब्धि अनलॉक करने में विफल: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/is-IS.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Ekki ólæst",
"toast_title": "Afrek opnuð!",
"error": {
"load_failed": "Mistókst að hlaða afrekum: ${message}"
"load_failed": "Mistókst að hlaða afrekum: ${message}",
"unlock_failed": "Mistókst að opna afrek: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Non sbloccato",
"toast_title": "Obiettivi sbloccati!",
"error": {
"load_failed": "Impossibile caricare gli obiettivi: ${message}"
"load_failed": "Impossibile caricare gli obiettivi: ${message}",
"unlock_failed": "Impossibile sbloccare l'obiettivo: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "ロックが解除されていません",
"toast_title": "実績のロックが解除されました!",
"error": {
"load_failed": "実績の読み込みに失敗しました: ${message}"
"load_failed": "実績の読み込みに失敗しました: ${message}",
"unlock_failed": "実績の解除に失敗しました: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "잠금 해제되지 않음",
"toast_title": "업적 잠금 해제!",
"error": {
"load_failed": "업적을 로드하지 못했습니다: ${message}"
"load_failed": "업적을 로드하지 못했습니다: ${message}",
"unlock_failed": "업적을 잠금 해제하지 못했습니다: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/lzh.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "尚未功成",
"toast_title": "功成!",
"error": {
"load_failed": "誊录功绩不成:${message}"
"load_failed": "誊录功绩不成:${message}",
"unlock_failed": "启功勋不成:${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Niet ontgrendeld",
"toast_title": "Prestaties ontgrendeld!",
"error": {
"load_failed": "Kan prestaties niet laden: ${message}"
"load_failed": "Kan prestaties niet laden: ${message}",
"unlock_failed": "Kan prestatie niet ontgrendelen: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Não desbloqueado",
"toast_title": "Conquistas desbloqueadas!",
"error": {
"load_failed": "Falha ao carregar conquistas: ${message}"
"load_failed": "Falha ao carregar conquistas: ${message}",
"unlock_failed": "Falha ao desbloquear a conquista: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Не разблокировано",
"toast_title": "Достижения разблокированы!",
"error": {
"load_failed": "Не удалось загрузить достижения: `${message}"
"load_failed": "Не удалось загрузить достижения: ${message}",
"unlock_failed": "Не удалось разблокировать достижение: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/uk-UA.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Не розблоковано",
"toast_title": "Досягнення розблоковано!",
"error": {
"load_failed": "Не вдалося завантажити досягнення: ${message}"
"load_failed": "Не вдалося завантажити досягнення: ${message}",
"unlock_failed": "Не вдалося розблокувати досягнення: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/vi-VN.json
Original file line number Diff line number Diff line change
Expand Up @@ -5480,7 +5480,8 @@
"locked": "Chưa mở khóa",
"toast_title": "Thành tích đã được mở khóa!",
"error": {
"load_failed": "Không tải được thành tích: ${message}"
"load_failed": "Không tải được thành tích: ${message}",
"unlock_failed": "Không mở khóa được thành tích: ${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -5492,7 +5492,8 @@
"locked": "未解锁",
"toast_title": "成就已解锁!",
"error": {
"load_failed": "加载成就失败:${message}"
"load_failed": "加载成就失败:${message}",
"unlock_failed": "解锁成就失败:${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
3 changes: 2 additions & 1 deletion src/public/locales/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -5479,7 +5479,8 @@
"locked": "未解鎖",
"toast_title": "成就已解鎖!",
"error": {
"load_failed": "載入成就失敗:${message}"
"load_failed": "載入成就失敗:${message}",
"unlock_failed": "解鎖成就失敗:${error}"
},
"achievements": {
"open_achievements_page": {
Expand Down
15 changes: 10 additions & 5 deletions src/public/pages/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ Markdown convertor traps (rehype order, `{:lang}`, trust tiers): [markdown-notes

## API & Communication

- **`endpoints.mjs`**: Core auth/system APIs (`login`, `register`, `whoami`, `getUserSetting`, etc.).
- **Global HTTP lives in `scripts/endpoints/`** (`base.mjs`, `parts.mjs`, `registries.mjs`, `server_events.mjs`, `p2p/evfsMedia.mjs`). Import via `/scripts/endpoints/…`. **Named functions only** — no path-string clients. Shell-local REST belongs in that shell’s `public/src/endpoints.mjs` / `endpoints/*` (see shells AGENTS).
- **No client-side timeouts on backend links.** Do not wrap local `/api/*` (or same-origin backend) `fetch` / WS with `AbortSignal.timeout`, artificial deadlines, or “give up if slow” logic. If the backend hangs or times out, that is a backend bug — fix the server, do not add frontend complexity to paper over it. UI supersession abort (e.g. user navigated away / started a newer enter) is fine; do not pass that signal into backend fetch just to simulate a timeout.
- **`endpoints/base.mjs`**: Core auth/system APIs (`login`, `register`, `whoami`, `getUserSetting`, etc.).
- **`endpoints/parts.mjs`**: `runPart`, `loadPart`, `getPartList`, `getPartDetails`, `setDefaultPart`.
- **`endpoints/server_events.mjs`**: `onServerEvent` — server-sent event bus.
- **`endpoints/registries.mjs`**: `GET /api/registries/:name` + dynamic `import()`.
- **`endpoints/p2p/evfsMedia.mjs`**: EVFS GET/PUT (`fetchEvfsFile`, `fetchMediaRef`, `uploadEvfsFile`, `uploadEvfsAttachment`). Pure URL helpers stay Deno-pure in chat `shared/evfsMedia.mjs` (`entityFileUrl`, `mediaRefUrl`).
- **`debug_log.mjs`**: `debugLog(name, data)` → `debug_logs/`.
- **`parts.mjs`**: `runPart`, `loadPart`, `getPartList`, `setDefaultPart`.
- **`server_events.mjs`**: `onServerEvent` — server-sent event bus.
- **HTML templates**: use `renderTemplate` / `mountTemplate` / `withTemplates` — never `fetch(…html)`.

## UI & Theming

Expand All @@ -32,6 +37,7 @@ Markdown convertor traps (rehype order, `{:lang}`, trust tiers): [markdown-notes
- **`contentReveal.mjs`**: `wrapSensitiveMediaHtml`, `wrapContentWarningHtml`, `bindContentReveal`.
- **`translate.mjs`**: `mountTranslationBlock`, `requestTranslation`, `resolveTargetLang` (-> `primaryLocale()`).
- **`toast.mjs`**: `showToast`, `showToastI18n`.
- **`errorHandlers.mjs`**: `handleError(i18nKey, toastParams?)` returns a `.catch` closure (toast + console + Sentry). Immediate form: `handleError(i18nKey, toastParams, error)`. **Only for fount faults** — user mistakes use `showToastI18n` directly. Backend twin: `fount/scripts/errorHandlers.mjs` (`handleError(error, ...extras)`).

## Rendering & Content

Expand All @@ -40,7 +46,6 @@ Markdown convertor traps (rehype order, `{:lang}`, trust tiers): [markdown-notes
- **`markdown/standaloneDocument.mjs`**: `renderMarkdownAsStandaloneDocument` / `wrapStandaloneMarkdownDocument` — offline full HTML for Chat/Social download/share/drag. Filenames from document `<title>` via `fileNameFromHtmlTitle` / `downloadHtmlDocument`.
- **`sanitizeHtml.mjs`**: `sanitizePermissiveHtml` — rich displayName HTML minus script / `style` / `on*` / dangerous URLs. `scrubHtmlActivePayload(string|root)` — string → `<template>` scrub → `DocumentFragment`; DOM root → in-place; strips `on*` / all `srcset` / unsafe URLs (keeps `style`). Prefer the string path over live-`innerHTML` then scrub. `isSafeHtmlUrl` rejects `javascript:` / `data:` / protocol-relative `//…` and `/\…`.
- **`embedCard.mjs`**: `ALL /api/no-cors?url=` + OG parse; `MutationObserver` hydration; session LRU. Proxy details: [markdown-notes.md](markdown-notes.md#no-cors-proxy).
- **`registries.mjs`**: `GET /api/registries/:name` + dynamic `import()`.
- **`emojiPicker.mjs`**: Shared emoji picker (click inserts token; Hub long-press/right-click sends sticker). Section headers / Alt·right-click on the rail open `emojiPackPreview`. Floating placement in `components/floatingPanel.mjs`. Hub mounts via `mountDockedEmojiPicker`.
- **`emojiPackPreview.mjs`**: Pack preview card (info + join/follow/favorite); `showEmojiPackPreview(anchor, { pack, provider, available })`.
- **`i18n.mjs`**: Sole public entry. Call `initTranslations()` early. Switch UI language with **`setLanguage(string[])`** (writes preferredLangs + reloads via platform `i18n/base.mjs`). Raw bundle without applying: **`loadLocaleData(string[])`** (fount → `/api/getlocaledata`; Pages → static `locales/*.json`). Prefer these over ad-hoc fetch. `data-i18n`, `geti18n`, `setElementI18n`, `primaryLocale()` (preferredLangs[0] → `main_locale`, default `en-UK`). Use for content locale / translation target — do not hardcode `zh-CN` or bare `navigator.language`. Missing keys → `console.warn('[i18n:missing] …')`; Playwright fixtures hard-fail on that prefix. Locale map slices: `matchLocale` / `getBestLocale` / `pickLocalizedSlice` (`i18n/locale_match.mjs`, same as backend). Params / placeholders: [i18n-notes.md](i18n-notes.md).
Expand All @@ -59,4 +64,4 @@ Markdown convertor traps (rehype order, `{:lang}`, trust tiers): [markdown-notes

## P2P (Browser)

Import via `esm.sh`. Shared primitives live in `shells/chat/public/shared/` (`/parts/shells:chat/shared/…`). Entity HTTP: `/api/parts/shells:chat/{viewer,entities…}`; network: `/api/p2p/{network,denylist,mailbox,federation}`.
Import via `esm.sh`. Shared primitives live in `shells/chat/public/shared/` (`/parts/shells:chat/shared/…`). EVFS URL helpers (`entityFileUrl` / `mediaRefUrl`) stay Deno-pure in chat `shared/evfsMedia.mjs`; browser fetch/upload is `/scripts/endpoints/p2p/evfsMedia.mjs`. Entity HTTP: `/api/parts/shells:chat/{viewer,entities…}`; network: `/api/p2p/{network,denylist,mailbox,federation}`.
2 changes: 1 addition & 1 deletion src/public/pages/base.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/
import * as Sentry from 'https://esm.sh/@sentry/browser'

import { onServerEvent } from './scripts/api/server_events.mjs'
import { onServerEvent } from './scripts/endpoints/server_events.mjs'

let skipBreadcrumb = false
if (!globalThis.fount?.test?.enabled) try {
Expand Down
2 changes: 1 addition & 1 deletion src/public/pages/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4" crossorigin="anonymous"></script>
<script type="module" src="/base.mjs"></script>
<script type="module">
import { getAnyDefaultPart } from './scripts/api/parts.mjs'
import { getAnyDefaultPart } from './scripts/endpoints/parts.mjs'
import { redirectToLoginInfo } from './scripts/host/credentialManager.mjs'
import { initTranslations } from './scripts/i18n/index.mjs'
import { setTheme } from './scripts/theme/index.mjs'
Expand Down
2 changes: 1 addition & 1 deletion src/public/pages/log_viewer/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { geti18n, initTranslations } from '/scripts/i18n/index.mjs'
import { createVirtualList } from '/scripts/lib/virtualList.mjs'
import { attachLogWire } from 'https://esm.sh/@steve02081504/virtual-console/wire/client'

import { ping } from '/scripts/api/base.mjs'
import { ping } from '/scripts/endpoints/base.mjs'
import { createLogsWs, openSource } from './endpoints.mjs'
import { renderLogItem, createLogToolbar, entryMatchesFilter } from './log.mjs'
import { initRepl, mountReplPanel } from './repl/index.mjs'
Expand Down
8 changes: 4 additions & 4 deletions src/public/pages/login/index.mjs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { initPasswordStrengthMeter } from '../scripts/components/passwordStrength.mjs'
import { createPOWCaptcha } from '../scripts/components/POWcaptcha.mjs'
import {
ping,
generateVerificationCode,
login,
register,
webauthnLoginBegin,
webauthnLoginComplete,
} from '../scripts/api/base.mjs'
import { getAnyDefaultPart } from '../scripts/api/parts.mjs'
import { initPasswordStrengthMeter } from '../scripts/components/passwordStrength.mjs'
import { createPOWCaptcha } from '../scripts/components/POWcaptcha.mjs'
} from '../scripts/endpoints/base.mjs'
import { getAnyDefaultPart } from '../scripts/endpoints/parts.mjs'
import { showToast } from '../scripts/features/toast.mjs'
import { retrieveAndDecryptCredentials, redirectToLoginInfo } from '../scripts/host/credentialManager.mjs'
import { initTranslations, console, savePreferredLangs, onLanguageChange } from '../scripts/i18n/index.mjs'
Expand Down
4 changes: 2 additions & 2 deletions src/public/pages/protocolhandler/index.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { authenticate } from '../scripts/api/base.mjs'
import { runPart } from '../scripts/api/parts.mjs'
import { authenticate } from '../scripts/endpoints/base.mjs'
import { runPart } from '../scripts/endpoints/parts.mjs'
import { initTranslations, console } from '../scripts/i18n/index.mjs'
import { applyTheme } from '../scripts/theme/index.mjs'

Expand Down
9 changes: 0 additions & 9 deletions src/public/pages/scripts/api/p2p/evfsMedia.mjs

This file was deleted.

4 changes: 2 additions & 2 deletions src/public/pages/scripts/components/partpath_picker.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getPartBranches, getPartDetails } from '../api/parts.mjs'
import { onServerEvent } from '../api/server_events.mjs'
import { getPartBranches, getPartDetails } from '../endpoints/parts.mjs'
import { onServerEvent } from '../endpoints/server_events.mjs'
import { geti18n } from '../i18n/index.mjs'

/**
Expand Down
Loading
Loading