mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-25 16:42:16 +03:00
* fix(providers): complete Hack Club AI removal from shared catalog (#11176) PR #11118/#11123 removed hackclub from the open-sse REGISTRY but the canonical shared catalog kept the entry, so the dashboard, alias resolver, icon registry, onboarding i18n strings and the generated provider reference kept advertising a provider the router no longer serves. Removed: - APIKEY_PROVIDERS hackclub entry (id + "hc" alias) in apikey/gateways.ts - hackclub from ProviderIcon KNOWN_SVGS + public/providers/hackclub.svg asset - providers.onboardingProviderDescriptions.hackclub from all 43 locales - stale comments referencing hackclub as a living provider (web-cookie.ts, registry/huggingchat, registry/g4f-groq, registry/freetheai, test prose) Count cascade 351 -> 350 (measured per-file; the live catalog union across all 11 provider collections goes 351 -> 350): - README.md, AGENTS.md, llm.txt + 42 i18n llm.txt mirrors (byte-identical bodies, docs-sync gate green), package.json description - docs/reference/PROVIDER_REFERENCE.md regenerated (gen-provider-reference) - canonical numbers in readme-hero/promise-pillars/comparison-table/ cli-terminal SVGs (docs-counts-sync STRICT gate green) Kept intentionally (historical records, not catalog): - CHANGELOG.md + docs/i18n/*/CHANGELOG.md entries from when the provider was added (#2339, #2611) — release history - src/lib/db/migrations/162_remove_hackclub_provider.sql — the removal migration itself - tests/unit/remove-hackclub-11118.test.ts — the REGISTRY removal guard Validation: new tests/unit/hackclub-removed.test.ts (5 asserts: catalog absence, hc alias free, structural grep over provider sources, icon/asset gone, i18n key gone) fails before / passes after; provider sibling tests 46 pass; provider-catalog consumer batch 268 pass; typecheck:core clean; eslint clean on touched files; check:provider-consistency OK (350 canonical); check:docs-counts-sync + check:docs-sync green. Closes #11176 * test(providers): align APIKEY split count after hackclub removal (232 -> 231) (#11176) --------- Co-authored-by: Xiangzhe <bakryun0718@proton.me>
140 lines
5.4 KiB
TypeScript
140 lines
5.4 KiB
TypeScript
/**
|
|
* #11176 — Hack Club AI (hackclub) must be FULLY removed from the live catalogs.
|
|
*
|
|
* PR #11118/#11123 removed the provider from the open-sse REGISTRY, but the
|
|
* canonical shared catalog (`src/shared/constants/providers/`) kept the entry,
|
|
* so the dashboard, the alias resolver, the icon set, the onboarding i18n
|
|
* strings and the generated provider reference kept advertising a provider the
|
|
* router can no longer serve. This test pins the complete removal:
|
|
*
|
|
* 1. no canonical catalog (API-key / web-cookie / OAuth / no-auth / local /
|
|
* search / audio / upstream-proxy / cloud-agent / system) has a `hackclub` entry;
|
|
* 2. no provider in any catalog claims the `hc` alias (it belonged to hackclub);
|
|
* 3. the provider/catalog source trees carry no `hackclub` mention at all
|
|
* (structural grep — catches comments referencing it as a living provider);
|
|
* 4. the icon registry and the shipped SVG asset are gone;
|
|
* 5. the onboarding i18n description key is gone (en + all locale mirrors).
|
|
*
|
|
* Historical mentions intentionally KEPT (release records, not catalog):
|
|
* CHANGELOG.md, docs/i18n/*\/CHANGELOG.md, and the removal migration
|
|
* src/lib/db/migrations/162_remove_hackclub_provider.sql (it IS the removal).
|
|
*/
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
import {
|
|
APIKEY_PROVIDERS,
|
|
WEB_COOKIE_PROVIDERS,
|
|
OAUTH_PROVIDERS,
|
|
FREE_PROVIDERS,
|
|
NOAUTH_PROVIDERS,
|
|
LOCAL_PROVIDERS,
|
|
SEARCH_PROVIDERS,
|
|
AUDIO_ONLY_PROVIDERS,
|
|
UPSTREAM_PROXY_PROVIDERS,
|
|
CLOUD_AGENT_PROVIDERS,
|
|
SYSTEM_PROVIDERS,
|
|
} from "../../src/shared/constants/providers.ts";
|
|
|
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
|
|
const CATALOGS: Record<string, Record<string, { id?: string; alias?: string }>> = {
|
|
APIKEY_PROVIDERS,
|
|
WEB_COOKIE_PROVIDERS,
|
|
OAUTH_PROVIDERS: OAUTH_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
FREE_PROVIDERS: FREE_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
NOAUTH_PROVIDERS: NOAUTH_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
LOCAL_PROVIDERS: LOCAL_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
SEARCH_PROVIDERS: SEARCH_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
AUDIO_ONLY_PROVIDERS: AUDIO_ONLY_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
UPSTREAM_PROXY_PROVIDERS: UPSTREAM_PROXY_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
CLOUD_AGENT_PROVIDERS: CLOUD_AGENT_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
SYSTEM_PROVIDERS: SYSTEM_PROVIDERS as Record<string, { id?: string; alias?: string }>,
|
|
};
|
|
|
|
function walk(dir: string): string[] {
|
|
const out: string[] = [];
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) out.push(...walk(full));
|
|
else if (/\.(ts|tsx|mts|json)$/.test(entry.name)) out.push(full);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
test("hackclub is absent from every canonical provider catalog", () => {
|
|
for (const [name, catalog] of Object.entries(CATALOGS)) {
|
|
assert.equal(
|
|
"hackclub" in catalog,
|
|
false,
|
|
`${name} still contains a hackclub entry (#11176)`
|
|
);
|
|
}
|
|
});
|
|
|
|
test("no provider in any catalog claims the `hc` alias (it belonged to hackclub)", () => {
|
|
const holders: string[] = [];
|
|
for (const [name, catalog] of Object.entries(CATALOGS)) {
|
|
for (const [key, p] of Object.entries(catalog)) {
|
|
if (p?.alias === "hc" || key === "hc") holders.push(`${name}:${key}`);
|
|
}
|
|
}
|
|
assert.deepEqual(holders, [], `alias "hc" still claimed by: ${holders.join(", ")}`);
|
|
});
|
|
|
|
test("no hackclub mention survives in the provider/catalog source trees", () => {
|
|
const scopedDirs = [
|
|
path.join(ROOT, "src", "shared", "constants", "providers"),
|
|
path.join(ROOT, "open-sse", "config"),
|
|
];
|
|
const offenders: string[] = [];
|
|
for (const dir of scopedDirs) {
|
|
for (const file of walk(dir)) {
|
|
if (/hack\s*club|hackclub/i.test(fs.readFileSync(file, "utf8"))) {
|
|
offenders.push(path.relative(ROOT, file));
|
|
}
|
|
}
|
|
}
|
|
assert.deepEqual(
|
|
offenders,
|
|
[],
|
|
`hackclub mentions left in catalog sources: ${offenders.join(", ")}`
|
|
);
|
|
});
|
|
|
|
test("hackclub icon registration and shipped SVG asset are gone", () => {
|
|
const iconSource = fs.readFileSync(
|
|
path.join(ROOT, "src", "shared", "components", "ProviderIcon.tsx"),
|
|
"utf8"
|
|
);
|
|
assert.equal(
|
|
/hackclub/i.test(iconSource),
|
|
false,
|
|
"ProviderIcon.tsx still registers hackclub (#11176)"
|
|
);
|
|
assert.equal(
|
|
fs.existsSync(path.join(ROOT, "public", "providers", "hackclub.svg")),
|
|
false,
|
|
"public/providers/hackclub.svg still shipped (#11176)"
|
|
);
|
|
});
|
|
|
|
test("onboarding i18n description for hackclub is gone from every locale", () => {
|
|
const messagesDir = path.join(ROOT, "src", "i18n", "messages");
|
|
const offenders: string[] = [];
|
|
for (const file of fs.readdirSync(messagesDir)) {
|
|
if (!file.endsWith(".json")) continue;
|
|
const messages = JSON.parse(fs.readFileSync(path.join(messagesDir, file), "utf8"));
|
|
const descriptions = messages?.providers?.onboardingProviderDescriptions;
|
|
if (descriptions && "hackclub" in descriptions) offenders.push(file);
|
|
}
|
|
assert.deepEqual(
|
|
offenders,
|
|
[],
|
|
`onboardingProviderDescriptions.hackclub still present in: ${offenders.join(", ")}`
|
|
);
|
|
});
|