Replace hardcoded `allow_origins=["*"]` with a parsed `CORS_ORIGINS`
environment variable (comma-separated). Default remains `*` for
backward compatibility — no existing deployment breaks — but the API
now logs a startup warning prompting users to set it explicitly for
production.
Exception handlers now route their CORS headers through a shared
`_cors_headers()` helper that mirrors Starlette's CORSMiddleware
behavior: reflects the request Origin when allowed (handling the
browser-rejected `*` + credentials combination correctly), and omits
`Access-Control-Allow-Origin` for disallowed origins so error bodies
don't leak cross-origin when `CORS_ORIGINS` is configured.
Closes#585, #730.
Based on the original work by Greg Grace in #597; rewritten on top of
current main to address prior review feedback (load_dotenv kept at
top, `import os` grouped with stdlib, `_cors_headers` defined before
its exception-handler callers, origins parsed once at module load)
and to choose a non-breaking default paired with a startup warning
instead of a stricter-by-default origin.
Co-authored-by: Greg Grace <ggrace@519lab.com>
* fix(docker): make wait-for-api.sh POSIX and enforce LF line endings (#586)
* fix: restore inline comment on final exit 0
Addresses review feedback: the comment on the final `exit 0` explains
a non-obvious design decision (frontend still starts when the API
never became ready, so users get a usable UI with connection errors
rather than a dead container).
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
* feat: make chunk sizing token-based with 512-token default
* fix: defer embedding debug token metrics
* chore: lower default chunk size to 400 tokens and document rationale
The previous 512-token default matched exactly the context window of
BERT-family embedders like mxbai-embed-large, leaving no margin for:
- tokenizer mismatch between our o200k_base measurement and the
embedder's own WordPiece tokenizer
- occasional splitter overshoot (RecursiveCharacterTextSplitter can
emit chunks slightly above chunk_size when separators are sparse)
- special tokens ([CLS], [SEP]) that consume context-window budget
400 tokens keeps ~20% headroom below 512 while still being a large
improvement over the old character-based default for most content.
Users with larger-context embedders can raise OPEN_NOTEBOOK_CHUNK_SIZE
via env var. Also adds a CHANGELOG entry for the full PR behavior
change.
* chore: move chunking changelog entry under 1.8.5
Target release is 1.8.5 — moving the Changed section out of Unreleased.
---------
Co-authored-by: Luis Novo <lfnovo@gmail.com>
* feat(i18n): add Spanish (es-ES) locale
Add complete Spanish translation covering all 930+ keys across
all UI sections: navigation, notebooks, sources, chat, search,
podcasts, transformations, settings, models, API keys, and error messages.
- Create es-ES locale file with full translation
- Register es-ES in locale index with LanguageCode type
- Add Spanish entry to LanguageToggle dropdown
- Add `spanish` key to common section in all existing locales
- Add date-fns Spanish locale for date formatting
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(i18n): use t() function accessor for Spanish dropdown item
Rebased onto main, which migrated i18n from the custom Proxy pattern to
react-i18next's t() function. Updates the new es-ES entry in
LanguageToggle to match the current accessor style so it renders the
translated label at runtime instead of undefined.
---------
Co-authored-by: chemazener <chemazener@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Luis Novo <lfnovo@gmail.com>
- Replace getApiErrorKey with getApiErrorMessage in use-settings.ts
so error toasts show translated messages instead of raw i18n keys
- Update CLAUDE.md files to reflect the new t('section.key') pattern
and remove outdated Proxy-related gotchas
- Replace Proxy-based useTranslation hook with thin react-i18next wrapper
- Convert all t.section.key property access to t('section.key') function calls across 84 files
- Migrate TranslationKeys type parameters to TFunction from i18next
- Update test setup mock and test assertions for new pattern
- Preserve setLanguage with language change events for loading overlay
Closes#579
- Catch only ValueError (decryption errors) instead of broad Exception
so NotFoundError and other failures propagate correctly
- Support migrate_to parameter in the fallback delete path so linked
models can be reassigned instead of always cascade-deleted
- Sanitize decryption_error message to not expose raw exception details
- Credential.get_all() now uses per-row error handling instead of failing on first bad row
- Broken credentials include decryption_error field with descriptive message
- DELETE endpoint falls back to direct DB delete when credential can't be decrypted
- Frontend shows amber warning alert for broken credentials with disabled test/edit/discover
- Added i18n translation keys for decryption error warning in all 9 locales
* fix: map base_url to endpoint for Azure credentials
The Azure credential form only exposes a base_url field, but the
connection tester, key provisioner, and Esperanto config all expect
an endpoint field. This maps base_url to endpoint for Azure providers
so credentials work without requiring a dedicated endpoint form field.
Closes#727
* docs: update Azure credential docs to reflect base_url mapping
Append os.sep to the directory path before startswith() check so that
paths like /app/data/uploads_evil/ cannot bypass the uploads directory
validation.
- Bump ai-prompter to >=0.4.0 which uses Jinja2 SandboxedEnvironment,
preventing arbitrary code execution via user-provided transformation prompts
- Sanitize uploaded filenames with os.path.basename() and validate resolved
path stays within upload directory to prevent path traversal
- Validate file_path in source creation is within UPLOADS_FOLDER to prevent
arbitrary file read via Local File Inclusion