mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 12:22:14 +03:00
* fix(electron): bump electron 42→43 + build better-sqlite3 from source (ABI 148) (#6605) fix(electron): bump electron 42→43 + rebuild better-sqlite3 from source against the Electron ABI (148). Electron 43 raises NODE_MODULE_VERSION to 148; better-sqlite3@12.11.1 has no electron-v148 prebuild, so the packaged app died with 'Nenhum driver SQLite disponível'. prepare-electron-standalone now compiles better-sqlite3 from source against the electron headers into build/Release (where 'bindings' resolves it). Validated by Electron Package Smoke (green) + local (node_register_module_v148). Supersedes #6378. (--admin: the only reds are SonarQube/SonarCloud failing on a coverage-report artifact digest-mismatch — a GitHub Actions infra flake, not this diff; Sonar is green on main and the diff touches only the electron build.) * deps: bump the development group across 1 directory with 6 updates (#6588) deps: bump the development group (6 updates). Rebased onto current main; all checks green after the electron-smoke fix (#6605). * fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump (#6620) fix(proxy): force CONNECT tunnel for HTTP proxied requests (undici 8.7) + production deps bump. undici 8.6+ changed ProxyAgent to forward plain-HTTP via request-proxy instead of CONNECT, breaking OAuth refresh through a connection proxy (501). proxyDispatcher now passes proxyTunnel:true. Validated: Unit Tests 3/8 (the OAuth-proxy test) green, new regression test green (fails without the fix on undici 8.7), SonarQube green. Supersedes #6380. (--admin: the only red is Electron Package Smoke failing on a next-build artifact 'digest-mismatch' — a GitHub Actions infra flake corrupting the asar ('file data stream has unexpected number of bytes'); the better-sqlite3 rebuild itself succeeded (gyp ok) and the electron path is unchanged from #6605 which passed the smoke. Not this diff.) * feat(provider): add OpenVecta AI inference gateway OpenVecta (https://openvecta.com/) is an OpenAI-compatible AI inference gateway hosting LLMs (GLM, Claude, DeepSeek, GPT OSS, Llama, Kimi, Nemotron...) plus text-embedding-* models behind a single Bearer key. Wiring (7 integration points): - src/shared/constants/providers/apikey/inference-hosts.ts: catalog entry - open-sse/config/providers/registry/openvecta/index.ts: registry w/ 9 seed LLMs - open-sse/config/providers/index.ts: wire into REGISTRY - src/app/api/providers/[id]/models/discovery/providerModelsConfig.ts: live /v1/models URL - src/app/api/providers/[id]/models/discovery/providerSets.ts: NAMED_OPENAI_STYLE_PROVIDERS - public/providers/openvecta.svg: brand icon - tests/unit/openvecta-provider-registration.test.ts: regression guard (6 tests, all pass) No executor needed — buildOpenAiCompatibleRegistryEntry wires format=openai / executor=default / authType=apikey / authHeader=bearer. Live catalog discovery uses the existing NAMED_OPENAI_STYLE_PROVIDERS path (live /v1/models fetch + registry seed as offline fallback). Validation: - npm run typecheck:core clean - npm run typecheck:noimplicit:core 4 errors in unchanged files (combo.ts, cliRuntime.ts); 0 in new code - npm run lint clean - node --import tsx/esm --test tests/unit/openvecta-provider-registration.test.ts 6/6 pass - sibling tests/unit/openai-style-providers-4239-4155-3841.test.ts 18/18 pass (no regression) * chore(merge): drop unrelated main-drift from PR fork + fix count/golden drift The fork branch predated main's electron 42→43 bump (#6605) and several other package.json/lockfile churn; those files are unrelated to the OpenVecta provider addition and were reintroducing an older/stale state (version 3.8.46, electron 42, older bun/eslint-config-next) that broke the Electron Package Smoke check. Restored package.json, package-lock.json, electron/package.json, electron/package-lock.json, and scripts/build/prepare-electron-standalone.mjs to match origin/release/v3.8.47. Also updates the two provider-count assertions (166->167) and regenerates the translate-path golden snapshot to account for the new openvecta entry. Co-authored-by: hajilok <120608486+hajilok@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com> Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
93 lines
4.1 KiB
TypeScript
93 lines
4.1 KiB
TypeScript
// Characterization of the providers.ts catalog split (god-file decomposition): the host became a
|
|
// barrel that re-exports 10 data catalogs now living under constants/providers/*, and APIKEY is
|
|
// merged from 6 semantic family files (apikey/<family>.ts). Locks: the public surface (every catalog
|
|
// + helpers still exported), the spread-merge integrity (167 APIKEY entries, no loss/dup), and that
|
|
// load-time Zod validation still runs. Pure-data move → behavior must be identical.
|
|
// Count was 171 before obsolete provider removals (PR #6675: glhf/kluster/cablyai/inclusionai etc.,
|
|
// 171->167) plus #6126 (ClinePass dual-auth): the API-key-only APIKEY_PROVIDERS_GATEWAYS entry was
|
|
// removed as a duplicate now that clinepass is OAuth-primary (OAUTH_PROVIDERS.clinepass) with its
|
|
// BYOK path admitted through the DUAL_AUTH_APIKEY_PROVIDER_IDS gate instead (167->166), then the
|
|
// OpenVecta inference-gateway addition brought it back to 167.
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const P = await import("../../src/shared/constants/providers.ts");
|
|
|
|
test("barrel still exports every catalog + key helpers", () => {
|
|
for (const name of [
|
|
"NOAUTH_PROVIDERS",
|
|
"OAUTH_PROVIDERS",
|
|
"WEB_COOKIE_PROVIDERS",
|
|
"APIKEY_PROVIDERS",
|
|
"LOCAL_PROVIDERS",
|
|
"SEARCH_PROVIDERS",
|
|
"AUDIO_ONLY_PROVIDERS",
|
|
"UPSTREAM_PROXY_PROVIDERS",
|
|
"CLOUD_AGENT_PROVIDERS",
|
|
"SYSTEM_PROVIDERS",
|
|
"AI_PROVIDERS",
|
|
"ALIAS_TO_ID",
|
|
"ID_TO_ALIAS",
|
|
"getProviderById",
|
|
"getProviderByAlias",
|
|
"resolveProviderId",
|
|
]) {
|
|
assert.ok(name in P, `missing export: ${name}`);
|
|
}
|
|
});
|
|
|
|
test("APIKEY_PROVIDERS merges the 6 family files into 167 entries (no loss / no dup)", async () => {
|
|
const keys = Object.keys((P as Record<string, object>).APIKEY_PROVIDERS);
|
|
assert.equal(keys.length, 167);
|
|
assert.equal(new Set(keys).size, 167, "duplicate keys after spread-merge");
|
|
// the merged object's entry-count equals the sum of the 6 semantic family files; families are a
|
|
// strict partition (every provider in exactly one), so the sum must be exactly 167.
|
|
const families: [string, string][] = [
|
|
["gateways", "APIKEY_PROVIDERS_GATEWAYS"],
|
|
["frontier-labs", "APIKEY_PROVIDERS_FRONTIER"],
|
|
["inference-hosts", "APIKEY_PROVIDERS_INFERENCE"],
|
|
["enterprise-cloud", "APIKEY_PROVIDERS_ENTERPRISE"],
|
|
["regional", "APIKEY_PROVIDERS_REGIONAL"],
|
|
["specialty-media", "APIKEY_PROVIDERS_SPECIALTY"],
|
|
];
|
|
let famTotal = 0;
|
|
const seen = new Set<string>();
|
|
for (const [file, exportName] of families) {
|
|
const mod = await import(`../../src/shared/constants/providers/apikey/${file}.ts`);
|
|
const famKeys = Object.keys(mod[exportName]);
|
|
famTotal += famKeys.length;
|
|
for (const k of famKeys) {
|
|
assert.ok(!seen.has(k), `provider ${k} appears in more than one family`);
|
|
seen.add(k);
|
|
}
|
|
}
|
|
assert.equal(famTotal, 167, "families must partition all 167 providers");
|
|
});
|
|
|
|
test("AI_PROVIDERS Proxy aggregates all sections; lookups resolve", () => {
|
|
const ai = (P as Record<string, Record<string, unknown>>).AI_PROVIDERS;
|
|
assert.ok(Object.keys(ai).length > 200);
|
|
assert.ok((P as Record<string, (id: string) => unknown>).getProviderById("openai"));
|
|
assert.ok((P as Record<string, (id: string) => unknown>).getProviderById("claude"));
|
|
// a moved catalog is reachable through the barrel re-export
|
|
assert.ok((P as Record<string, Record<string, unknown>>).APIKEY_PROVIDERS["openai"]);
|
|
});
|
|
|
|
test("each extracted data module is importable on its own", async () => {
|
|
const mods = [
|
|
["noauth", "NOAUTH_PROVIDERS"],
|
|
["oauth", "OAUTH_PROVIDERS"],
|
|
["web-cookie", "WEB_COOKIE_PROVIDERS"],
|
|
["local", "LOCAL_PROVIDERS"],
|
|
["search", "SEARCH_PROVIDERS"],
|
|
["audio", "AUDIO_ONLY_PROVIDERS"],
|
|
["upstream-proxy", "UPSTREAM_PROXY_PROVIDERS"],
|
|
["cloud-agent", "CLOUD_AGENT_PROVIDERS"],
|
|
["system", "SYSTEM_PROVIDERS"],
|
|
];
|
|
for (const [file, name] of mods) {
|
|
const m = await import(`../../src/shared/constants/providers/${file}.ts`);
|
|
assert.ok(m[name] && typeof m[name] === "object", `${file}.ts must export ${name}`);
|
|
}
|
|
});
|