Commit Graph

4127 Commits

Author SHA1 Message Date
diegosouzapw
8f0615fd04 fix(security): resolve 5 CodeQL alerts, document FPs, harden deploy skills
Real fixes (alerts auto-close on next scan):
- agentSkills/generator: escape backslash before double-quote in YAML
  frontmatter so a trailing backslash can't escape the closing quote
  (js/incomplete-sanitization #297/#298)
- usage: replace /\s*\(RESTRICTED\)\s*$/ with a non-backtracking literal +
  trim (js/polynomial-redos #275)
- i18n/request: skip __proto__/constructor/prototype in deepMergeFallback
  (js/prototype-pollution-utility #274)
- scripts/ad-hoc/nvidia diag: log key presence only, never key chars
  (js/clear-text-logging #273)
- tests: regression coverage for all three production fixes (YAML round-trip,
  proto-pollution guard, RESTRICTED strip + ReDoS timing)

Docs:
- ARCHITECTURE.md: executor count 45->55, OAuth modules 15->16, agy.ts in list

Deploy skills (deploy-vps-*-cc/-cx/-ag): add --legacy-peer-deps (npm v11
peer-dep resolver crashes on the omniroute tree) and replace the
"; pm2 start" that masked a failed install with a proper && chain.
2026-06-01 19:36:48 -03:00
Paijo
2a8954663c fix(claude-web): inject cf_clearance into cookie for 403 prevention (#3046)
The execute() and testConnection() methods called
normalizeClaudeSessionCookie() which does NOT inject cf_clearance.
Cloudflare pins cf_clearance to TLS fingerprint — without it, requests
get challenged with 403 even with valid session cookies.

Changed both call sites to use normalizeClaudeSessionCookieWithAutoRefresh()
which auto-injects cf_clearance via Turnstile solver when missing.

Fixes: [403]: Claude Web API error:

Co-authored-by: oyi77 <oyi77@users.noreply.github.com>
2026-06-01 18:14:39 -03:00
diegosouzapw
a1c743ddb0 chore(release): v3.8.8 — changelog from v3.8.7, version sync, i18n + env-doc fixes
- bump package.json / open-sse / electron / openapi / llm.txt to 3.8.8
- restructure CHANGELOG: Unreleased -> [3.8.8], dedup broken Notion/MCP block (was 12x)
- add every PR since v3.8.7 that was missing: Quota Share Engine (#2859/#3022/#3032),
  page redesigns (#2827/#2839/#2847/#2849/#2869/#2873), and fixes #2960/#2973/#2984/
  #3021/#3029/#3031/#3035/#3036/#3037/#3039/#3043/#3028; folded #2978/#2988/#3041
- insert [3.8.8] section into all 41 i18n CHANGELOGs + sync llm.txt mirrors
- document OMNIROUTE_PLUGINS_ALLOW_EXEC in .env.example + ENVIRONMENT.md (env-doc-sync gap)
2026-06-01 17:11:21 -03:00
Paijo
9e7f3cad10 feat(plugins): plugin hook wiring + comprehensive test suite + welcome-banner example (#3045)
Follow-up to the plugins framework (#3041): wires the plugin hooks end-to-end and adds full test coverage.

- Wires `onRequest` / `onResponse` / `onError` hooks into the chat pipeline (`chatCore` now imports from the unified `hooks` registry).
- Loads active plugins on server startup (`pluginManager.loadAll()` in `server-init`) so they survive restarts.
- Ships a `welcome-banner` example plugin (`examples/plugins/`) + test fixture.
- Adds a comprehensive plugin test suite (manifest, db, config, hooks, manager lifecycle, loader IPC, permissions, scanner, welcome-banner e2e).

Integration fixes applied during review:
- `manager.install` now removes an orphaned `destDir` (DB row gone but files left on disk) before the atomic rename, guarded by path containment — it previously failed with `ENOTEMPTY` (a regression surfaced by the new lifecycle test).
- `plugins-db` / `plugins-manager-lifecycle` tests now initialize the DB via the real migration `076` (`getDbInstance`) rather than relying on ambient state, so a missing/renumbered migration fails loudly instead of being masked.

348/348 plugin tests pass; typecheck / cycles clean.

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
2026-06-01 16:20:11 -03:00
Diego Rodrigues de Sa e Souza
20c31493af feat(plugins): plugins framework + per-API-key disable-non-public-models (#3041)
Integrates two community contributions into release/v3.8.8 with security hardening and conflict resolution.

- **Plugins framework** (#2913 — thanks @oyi77): hooks + registry unification, plugin SDK (`definePlugin`), worker-thread sandbox, per-plugin hook rate limiting, SHA-256 integrity verification, semver-gated upgrade, and execution analytics. Plugin routes are loopback-only (`isLocalOnlyPath`); `child_process` exec is opt-in via `OMNIROUTE_PLUGINS_ALLOW_EXEC` (default off).
- **API key option: disable non-published models** (#3017 — thanks @androw): a per-key flag restricting the key to discovered public models (combos / `auto/*` / `qtSd/*` routing still allowed).

Hardening applied during integration: migration renumber (089/090/091), `/api/plugins` LOCAL_ONLY route-guard classification (closes the plugin-RCE vector), atomic install/upgrade with path containment, `O_EXCL` tmp-file creation (TOCTOU), rate-limit-map eviction, `validatePluginConfig` on configure, `buildErrorBody` on all plugin error paths. 246/246 tests; typecheck / cycles / docs-sync clean.

Co-authored-by: oyi77 <14921983+oyi77@users.noreply.github.com>
Co-authored-by: Nicolas Lorin <androw95220@gmail.com>
2026-06-01 15:43:55 -03:00
Paijo
89c52d4f04 fix: resolve pre-existing test failures (env sync, PII, quota, sidebar) (#3039)
Integrated into release/v3.8.8. 9 legit test alignments + 34 new test files kept; restored 5 masked assertions (sk_ key redaction, circular/SSN redaction, T24 wait-log, THEORY-004 SSE, relay handoff) to strict/meaningful checks. Thanks @oyi77!
2026-06-01 14:52:50 -03:00
Hernan Javier Ardila Sanchez
482e4690eb fix(dashboard): use lightweight ping endpoint for MaintenanceBanner (fixes #3040) (#3043)
Integrated into release/v3.8.8. Applied review fixes: moved the SELECT 1 into a pingDb() db helper (no raw SQL in route, Hard Rule #5) + the 503 catch no longer leaks err.message (Hard Rule #12). Thanks @herjarsa!
2026-06-01 14:31:42 -03:00
diegosouzapw
4e4e89759a chore: ignore local cache and workspace helper directories
Add local-only cache, IDE, mono-repo, references, and task directories to .gitignore to prevent development artifacts from being committed.
2026-06-01 13:35:29 -03:00
Chewji
6b7ae9ad2e fix(mcp): resolve streamable http transport readiness offline status (#3037)
Integrated into release/v3.8.8. Fixes MCP streamable-HTTP transport readiness reporting when offline + session sweep. Thanks @Chewji9875!
2026-06-01 09:59:23 -03:00
dangeReis
e11366b647 fix(privacy): resolve PII feature flag correctly and fix PII response sanitization in streaming SSE requests (#3021)
Integrated into release/v3.8.8. Fixes the PII feature-flag resolution + adds streaming-aware SSE PII sanitization (rolling-window transform, obfuscation-hardened regexes, Luhn/CPF/CNPJ checks). Applied review fixes: block-mode + fallback errors no longer leak pattern types / upstream err.message into stream errors (Hard Rule #12); typed the createPiiTransform cast (no any); fixed a string===boolean type error; dropped the generated .source/* files. Thanks @dangeReis!
2026-06-01 08:22:09 -03:00
Andrianata Daud
6561548687 fix(docker): warn-only on /app/data permission check, remove exit 1 (#3036)
Integrated into release/v3.8.8. Docker /app/data permission check is now warn-only (no exit 1 crash-loop on first run) + UID hint uses $(id -u):$(id -g). The mcp-tools-43.svg part was already in the release. Thanks @wussh!
2026-06-01 08:12:19 -03:00
Muhammad Tamir
b20748a73e Fix DuckDuckGo Missing Api Key & Update OpenCode Free Model List (#3008)
Integrated into release/v3.8.8. The DuckDuckGo noAuth bypass + OpenCode free-model refresh were already integrated earlier (you're credited in CHANGELOG); this squashes your branch in for the Merged badge. Thanks @NekoMonci12!
2026-06-01 08:11:23 -03:00
Insomnia
baa4e56997 fix: improve macOS Electron window chrome (#3029)
Integrated into release/v3.8.8. macOS Electron window-chrome: tray icon template + draggable header region (excludes interactive controls) with a safe fallback + MutationObserver cleanup. Squash-merged (drops the AI co-author trailers per repo policy). Thanks @bobbyunknown!
2026-06-01 08:08:01 -03:00
mi
57dfa25312 fix(oom): prevent per-request memory accumulation (256MB heap) (#2973)
Integrated into release/v3.8.8. OOM fix: truncateForLog caps logged bodies at 8KB (prevents multi-MB clone accumulation across log call-sites) + a heap-pressure 503 guard. Applied review fix: the 503 body no longer leaks the heap figure (Hard Rule #12) — logged internally instead. Thanks @soyelmismo!
2026-06-01 08:07:03 -03:00
Tentoxa
aa8033dae9 chore: bump Claude Code identity to 2.1.158 + sync anthropic-beta flags from live captures (#3010)
Integrated into release/v3.8.8 — free_tier_exhausted error rule (identity/beta-flags already in release). Thanks @Tentoxa!
2026-06-01 07:57:55 -03:00
CitrusIce
c34285f676 fix(stream): drop leaked chat bootstrap chunk for responses clients (#3035)
Integrated into release/v3.8.8. Drops the leaked empty chat.completion.chunk bootstrap frame before response.* SSE events so strict /v1/responses clients (OpenCode) don't fail on the first frame. Thanks @CitrusIce!
2026-06-01 07:56:25 -03:00
Yuriy Bilous
8ef8a9b5a7 fix(i18n): complete Ukrainian (uk-UA) UI translation coverage (#2988)
Integrated into release/v3.8.8. Applied your Ukrainian translations across the current uk-UA.json structure (709 keys improved from English/__MISSING__ to proper Ukrainian), preserving release's latest key set. Thanks @Lion-killer!
2026-06-01 07:55:03 -03:00
guanbear
dd42b1564f Fix missing API key scope translations (#3031)
Integrated into release/v3.8.8. Fills the 7 apiManager.* self-service scope keys (managementAccessDesc, selfServiceVisibility(+Desc), ownUsageVisibility(+Desc), sharedAccountQuotaVisibility(+Desc)) across 41 locales + regression test. Resolved conflicts against the current release on your branch. Thanks @guanbear!
2026-06-01 07:50:58 -03:00
Paijo
e4eeb6dc7f refactor: Make SessionPool modular & provider-agnostic (#2978)
Integrated into release/v3.8.8. Applied review fixes: typed DefaultExecutor.execute(input: ExecuteInput), guarded result?.response?.status, removed the unused cloakbrowser dependency. Session-pool modular refactor + 36 tests green. Thanks @oyi77!
2026-06-01 07:44:52 -03:00
Paijo
4de674e0fc test: increase coverage to >60% — 353 new test cases (#3018)
Integrated into release/v3.8.8 — 122 new passing tests (DB core/models/settings, executor base, stream payload collector, model resolver). Thanks @oyi77!
2026-06-01 07:39:09 -03:00
Diego Rodrigues de Sa e Souza
099cb67317 Merge pull request #3032 from diegosouzapw/feat/quota-share-v2
feat(quota): Quota Share v2 — nav move, 3-col grouped layout, endpoints+key preview, full pool edit
2026-06-01 07:03:14 -03:00
diegosouzapw
a332b659c2 Revert "chore(quota): remove orphaned groupAllocationNote i18n key (EditAllocationsModal retired)"
This reverts commit 6fd7098c21.
2026-06-01 03:27:06 -03:00
diegosouzapw
6fd7098c21 chore(quota): remove orphaned groupAllocationNote i18n key (EditAllocationsModal retired) 2026-06-01 03:24:57 -03:00
diegosouzapw
df7b1e83c2 feat(quota): available-endpoints card + per-key model preview 2026-06-01 03:22:54 -03:00
diegosouzapw
6848636351 feat(quota): edit button opens full PoolWizard (exclusive-preserving); retire EditAllocationsModal
- PoolWizard: add editPoolExclusive prop; pre-fill uses editPoolExclusive ?? false so editing an exclusive pool keeps it exclusive instead of silently clearing the flag
- QuotaSharePageClient: wire editing state to a second <PoolWizard editPool=... editPoolExclusive=...>; compute editingExclusive from apiKeys.allowedQuotas; remove EditAllocationsModal import and handleSaveAllocations
- Delete EditAllocationsModal.tsx (fully subsumed by PoolWizard step 3)
- Tests: quota-email-privacy + quota-groups-ui + quota-pool-wizard updated to reflect retirement; new quota-edit-opens-wizard.test.ts (9 source-scan assertions)
2026-06-01 03:15:21 -03:00
diegosouzapw
3c8e84d702 feat(quota): all-groups default + stacked group sections + 3-col cards
- selectedGroupId defaults to "all" instead of "group-demo"
- <select> prepends <option value="all">{t("allGroups")}</option>
- Pool list replaced by groupsToRender map: one stacked section per group
  (heading: group name + count via groupPools.length), each with a
  grid-cols-1 md:grid-cols-2 xl:grid-cols-3 card grid
- Rename button guard changed from selectedGroupId !== "group-demo" to
  selectedGroupId !== "all" (no single target when viewing all groups)
- i18n: allGroups added to en.json ("All groups") + pt-BR.json ("Todos os grupos")
- quota-share-layout-v2.test.ts: 10 source-scan + i18n parity assertions
- quota-groups-ui.test.ts: align group heading test to groupPools.length
2026-06-01 03:03:03 -03:00
Diego Rodrigues de Sa e Souza
46c482ca98 Merge PR 3030 into release/v3.8.8 2026-06-01 03:02:34 -03:00
diegosouzapw
ac5ac0c2a7 fix(api): guard rotating providers in manual token-refresh route (Codex family-revocation)
POST /api/providers/[id]/refresh was the last unguarded proactive-refresh
entry point for rotating-refresh providers. The dashboard auto-refreshes every
expiring connection on a page load (and an old cached frontend bulk-calls this
endpoint), so each Codex account's single-use refresh_token got rotated; Auth0
then revoked the whole token family (openai/codex#9648) — every account but the
last died with [403] <!DOCTYPE. refreshAndUpdateCredentials (quota-sync) and the
connection-test route were already guarded; this closes the gap.

The route now skips proactive rotation when rotationGroupFor(provider) !== null
and returns {success,skipped,message}, deferring genuine expiry to the reactive,
serialized 401 path. Non-rotating providers keep refreshing on demand.

Test: codex-manual-refresh-rotating-guard (source-assertion, matches the
token-refresh-race-comprehensive #2941 style).
2026-06-01 03:00:13 -03:00
diegosouzapw
b64489b3ad feat(quota): PoolWizard editPool mode (full pool edit via PATCH)
- Add `editPool?: QuotaPool` to PoolWizardProps; import QuotaPool type
- Open effect pre-fills state (connectionIds, name, groupId, allocations,
  plan dims) from editPool; create-reset unchanged when editPool absent
- handleFinish branches on editPool: create path keeps POST→PUT→PATCH
  unchanged; edit path sends a single PATCH (name+groupId+connectionIds+
  allocations+exclusive) then optional PUT when dimensionsEdited
- Title uses t("editPoolTitle"), submit button uses t("saveChanges") in edit mode
- Add editPoolTitle/saveChanges to en.json and pt-BR.json (quotaShare namespace)
- New source-scan test: quota-pool-wizard-edit.test.ts (15 assertions, all pass)
2026-06-01 02:52:51 -03:00
diegosouzapw
881a8e9b56 feat(quota): move Quota Share nav item under Provider Quota 2026-06-01 02:43:59 -03:00
diegosouzapw
342f12b77a feat(quota): GET /api/quota/keys/[id]/models — preview the qtSd/ models a key sees 2026-06-01 02:39:37 -03:00
diegosouzapw
e5392a7eaa fix(quota): pool PATCH prunes OLD group/provider combos before re-sync (no orphan qtSd/ on switch) 2026-06-01 02:35:26 -03:00
diegosouzapw
e694674851 feat(quota): pool PATCH accepts groupId + connectionIds, re-syncs combos on connection change 2026-06-01 02:28:21 -03:00
Diego Rodrigues de Sa e Souza
bf96769db7 Merge pull request #3028 from diegosouzapw/docs/mcp-tools-43
docs(mcp): regenerate mcp-tools diagram for 43 tools + fix count
2026-06-01 00:16:13 -03:00
diegosouzapw
74e290bc70 docs(mcp): regenerate mcp-tools diagram for 43 tools (+ notion); fix count in CLAUDE.md
release/v3.8.8 added notionTools.ts (6 tools) → MCP total is 43, not 37, but the
diagram asset (mcp-tools-43.svg) was never generated and MCP-SERVER.md/CLAUDE.md
still said 37. Create mcp-tools-43.{mmd,svg} (rendered via mermaid-cli), repoint
MCP-SERVER.md + docs/diagrams/README.md, update CLAUDE.md count to 43, and remove
the superseded mcp-tools-37 source/asset.

Note: full 'next build' OOM'd locally (session cgroup limit); the SVG ref resolves
(file present at path) and check:docs-sync passes — CI runs the authoritative build.
2026-06-01 00:15:20 -03:00
diegosouzapw
a0b435bcae chore: credit PRs 3000, 3006, 3008, 3010, 3012, 3015, 3018 in changelog 2026-05-31 22:19:27 -03:00
Diego Rodrigues de Sa e Souza
4b3987e190 Merge pull request #3022 from diegosouzapw/feat/quota-share-redesign
feat(quota): Pool Groups + correções de enforcement → v3.8.8 (+ authz peer-IP, screen fixes)
2026-05-31 22:05:18 -03:00
diegosouzapw
7f6e7a80e3 fix(docs): point MCP-SERVER diagram to existing mcp-tools-37.svg (merge unbroke build)
release/v3.8.8 referenced ../diagrams/exported/mcp-tools-43.svg (43 tools, after
notionTools added) but never generated the asset — only mcp-tools-37.svg exists,
so the merged tree failed 'next build' with Module not found. Point the image +
source back to the existing 37 asset with a note that the count of record is 43
(per the source-of-truth breakdown). Follow-up: regenerate mcp-tools-43.{mmd,svg}.
2026-05-31 21:21:14 -03:00
diegosouzapw
58a7d97b3f Merge branch 'release/v3.8.8' into feat/quota-share-redesign
# Conflicts:
#	src/lib/db/apiKeys.ts
#	src/lib/db/migrationRunner.ts
#	src/server/authz/policies/management.ts
#	src/server/authz/routeGuard.ts
#	tests/unit/route-guard-private-lan.test.ts
2026-05-31 21:08:30 -03:00
diegosouzapw
137d77cf12 feat(quota): group selector + grouped pool cards + wizard group pick (Interface A)
Task B9: QuotaSharePageClient fetches /api/quota/groups, renders a group bar
(select + New group + Rename group actions), and filters pool cards by the
selected group. PoolWizard adds a group picker in step 1 and POSTs groupId;
default pool name now uses provider slug instead of the raw connection
label/email. EditAllocationsModal adds a group allocation note. i18n parity
for 7 new quotaShare keys in en + pt-BR. PoolCreateSchema gains optional
groupId field. Test: tests/unit/quota-groups-ui.test.ts (21 source-scan
assertions, all green).
2026-05-31 19:52:00 -03:00
diegosouzapw
5d84a8fa7a test(quota): combo protection guard matches qtSd/ prefix 2026-05-31 19:33:24 -03:00
diegosouzapw
efa8f0af23 feat(quota): /api/quota/groups CRUD (rename re-syncs combos)
Add GET/POST /api/quota/groups and PATCH/DELETE /api/quota/groups/[id].
PATCH rename calls renameGroup then re-syncs quotaShared-* combos (via
dynamic-import syncQuotaCombos) for every pool in the group, since combo
names embed the group slug. DELETE maps the deleteGroup throw (protected
group-demo or pools still referencing the group) to 409 Conflict via
buildErrorBody — never 500. All handlers are management-gated via
requireManagementAuth and route all errors through buildErrorBody (Hard
Rule #12). 37-assertion source-scan test verifies auth, error sanitisation,
response shapes, Zod validation, PATCH re-sync wiring, and DELETE 409 logic.
2026-05-31 19:31:30 -03:00
diegosouzapw
eac24ca458 feat(quota): group-level allocations + group access enforcement
upsertAllocations now propagates allocation rows to every pool in the
same group. A key allocated to pool A in group G automatically gets
an allocation row in pool B (same group), so enforceQuotaShare finds
the row when the key calls pool B's model and applies fair-share.

No change to apiKeyPolicy Check 3 (already group-correct via B5
groupSlug logic) or enforce.ts pool-match (works once propagation
supplies the row).
2026-05-31 19:24:59 -03:00
Diego Rodrigues de Sa e Souza
9863000ab1 Merge PR 3019 into release/v3.8.8 2026-05-31 19:16:46 -03:00
diegosouzapw
e9cc53b17f feat(quota): key scope + /v1/models expand to the whole group (real group)
- `getPoolsByGroup(groupId)` in quotaPools.ts: SELECT all pools for a group,
  exposed as public API and re-exported from localDb.ts.
- `resolveQuotaKeyScope`: pool → group → all pools in group expansion.
  The returned `poolSlugs` field now holds GROUP slugs (quotaGroupSlug of the
  group name) instead of individual pool-name slugs, one per distinct group.
  Group slug included only when the group has ≥1 valid connection (group-level
  anyValidConnection gate). Deduplication: a key in 2 pools of the same group
  expands once.
- `filterModelsToQuotaPools` (quotaCombos.ts): already matches by
  `parsed.groupSlug` ∈ poolSlugs — no logic change needed, just test alignment.
- quota-key-resolve.test.ts: updated 4 tests that asserted pool-name slugs
  (testpoola2, poolmix, etc.) to assert the group slug ("groupdemo") — this is
  alignment to the B5 group semantics, not masking; the assertions were correct
  for the old pool-slug behavior and are now correct for the new group-slug
  behavior.
- quota-catalog-filter.test.ts: updated fixtures from old quotaShared-* format
  to qtSd/<groupSlug>/... (naming changed in B3, test was already broken before B5).
2026-05-31 19:15:16 -03:00
diegosouzapw
6d2e695882 fix(sse): stop Codex multi-account family-revocation cascade on quota-sync
The Quota / Providers dashboard (POST /api/usage/provider-limits ->
syncAllProviderLimits, GET /api/usage/[connectionId]) calls
refreshAndUpdateCredentials() per connection, in concurrent chunks. For
rotating-refresh providers (Codex/OpenAI share one Auth0 client_id) the
single-use refresh_token is rotated on every refresh; refreshing siblings
concurrently makes Auth0 revoke the whole token family (openai/codex#9648),
killing every account but the last with [403] <!DOCTYPE html>. On the affected
VM expires_at was persisted as ~0 so needsRefresh() was effectively always
true -> every codex account refreshed on every page visit -> guaranteed cascade.

Fix #1: refreshAndUpdateCredentials skips proactive refresh for rotating
providers (rotationGroupFor) and reuses the current access_token for the quota
fetch; genuine expiry is handled by the reactive, serialized 401 path.

Fix #2 (defense in depth): serializeRefresh inserts a settle gap between two
QUEUED sibling refreshes (default 2000ms, CODEX_REFRESH_SPACING_MS, '0' to opt
out) but releases a lone refresh immediately, adding no latency to the reactive
request path.

Tests: codex-quota-sync-no-proactive-refresh (skip + non-rotating guard),
refresh-serializer-spacing (default/opt-out + lone-vs-queued behavior).
2026-05-31 19:13:41 -03:00
diegosouzapw
fc6692925e feat(quota): group-aware quotaShared combos (qtSd/<group>/...) with provider-scoped prune
- resolvePoolForSync now resolves groupName via getGroupName(pool.groupId),
  falling back to pool.name when the group record is missing.
- Both quotaModelName calls in syncQuotaCombos use groupName instead of
  pool.name, so combos are named qtSd/<groupSlug>/<provider>/<model>.
- Prune is now scoped to group+provider: syncing pool A (openrouter) never
  deletes pool B (baidu) combos that share the same group.
- removeQuotaCombosForPool likewise scoped to group+provider.
- Updated quota-combos-sync, quota-combo-balancing, quota-combo-cli-providers
  tests for the new group-slug naming.
- New tests/unit/quota-combo-groups.test.ts: G1–G4 cover two-pool same-group
  naming, provider-scoped prune isolation, default-group fallback, and stale
  prune within the same group+provider.
2026-05-31 19:02:32 -03:00
diegosouzapw
cb1a18fa1a feat(quota): qtSd/<group>/<provider>/<model> model naming
Replace the old quotaShared-<poolSlug>-<provider>/<model> format with
qtSd/<groupSlug>/<provider>/<model>. Adds quotaGroupSlug() as the canonical
helper; keeps quotaPoolSlug() as a delegating alias so existing callers
(quotaKey.ts, quotaCombos.ts) compile without changes. parseQuotaModelName
now returns { groupSlug, provider, model }. Updates quotaCombos.ts,
apiKeyPolicy.ts, and all tests that referenced the old field name or the
old hardcoded prefix literal.
2026-05-31 18:48:41 -03:00
diegosouzapw
1eff658678 feat(quota): quotaGroups DB module (CRUD)
Add src/lib/db/quotaGroups.ts with createGroup/getGroup/getGroupName/
listGroups/renameGroup/deleteGroup; deleteGroup guards against non-empty
groups (throws /pools/i) and protects the 'group-demo' seed. Re-export
all functions + QuotaGroup type from localDb.ts. 15 unit tests in
tests/unit/quota-groups-crud.test.ts all passing.
2026-05-31 18:32:50 -03:00
diegosouzapw
727616b2c0 feat(quota): quota_groups table + pools.group_id (migration 087)
Introduces first-class quota Group entity: new quota_groups table,
quota_pools.group_id column, GroupDemo seed, backfill of existing
pools, and groupId in QuotaPool/PoolCreate/PoolUpdate with a
group-demo default. Migration runner gains an isSchemaAlreadyApplied
guard for version 087.
2026-05-31 18:28:12 -03:00