mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Release v3.8.33 (#4515)
Release v3.8.33 — full CHANGELOG in the PR body. Blocking gates green (Build, Lint, Unit Tests 8/8, Package Artifact, Quality Gates, Quality Ratchet, Docs Sync, PR Test Policy, test-vitest). Admin-merged over a Node 26 future-compat timer flake (1/4) + an E2E UI flake (3/9) — both verified non-deterministic; full test:unit validated locally (16936 pass).
This commit is contained in:
committed by
GitHub
parent
bfaf459f3c
commit
ee24eb52d4
@@ -47,7 +47,7 @@ export const INTENTIONALLY_INTERNAL = new Set([
|
||||
"comboForecast", // intentionally-internal: src/lib/usage/comboForecast.ts
|
||||
"commandCodeAuth", // intentionally-internal: 5 API routes em /api/providers/command-code/auth/*
|
||||
"compression", // intentionally-internal: 2 API routes (settings/compression, context/rtk/config)
|
||||
"compressionScheduler", // DEAD?: 0 importers na auditoria de 2026-06-11; mantido para schema reservation
|
||||
"vacuumScheduler", // intentionally-internal: src/instrumentation-node.ts (dynamic import, lifecycle wiring per Rule #2)
|
||||
"detailedLogs", // intentionally-internal: 3 callers (callLogs.ts, logs/detail route, embeddings handler)
|
||||
"discovery", // DEAD?: 0 importers na auditoria de 2026-06-11; lib/discovery/index.ts não usa db/discovery
|
||||
"domainState", // intentionally-internal: 5 callers (batchWriter, circuitBreaker, costRules, fallbackPolicy, lockoutPolicy)
|
||||
@@ -59,6 +59,7 @@ export const INTENTIONALLY_INTERNAL = new Set([
|
||||
"obsidian", // intentionally-internal: src/lib/obsidianSync.ts + settings/obsidian route + MCP obsidianTools.ts
|
||||
"pluginMetrics", // DEAD? (production): write path não foi conectado ainda (documentado no cabeçalho do módulo); testado por tests/unit/plugins-metrics.test.ts
|
||||
"prompts", // DEAD? (production): zero callers de produção encontrados; domínio domain/prompts.ts é independente; testado por tests/integration/proxy-pipeline.test.ts
|
||||
"providerNodeSelect", // db-internal: importado só por db/providers.ts (selectProviderNodeForConnection — lógica pura de seleção de provider node split do providers.ts, #4421)
|
||||
"providerStats", // intentionally-internal: src/app/api/provider-stats/route.ts
|
||||
"recovery", // intentionally-internal: bin/cli/runtime.mjs (import() dinâmico) + tests
|
||||
"secrets", // intentionally-internal: src/instrumentation-node.ts (import() dinâmico na inicialização)
|
||||
|
||||
@@ -195,6 +195,9 @@ const DOC_ONLY_ALLOWLIST = new Set([
|
||||
// Source-code constants referenced in the docs narrative for the local
|
||||
// endpoints / route-guard classification (PR-3 in #3932).
|
||||
"LOCAL_ONLY_API_PREFIXES",
|
||||
// SQL keyword mentioned in the new VACUUM scheduler docs (#4437).
|
||||
// The check's regex picks up the bare word in description text.
|
||||
"VACUUM",
|
||||
]);
|
||||
|
||||
// Vars present in .env.example but intentionally absent from ENVIRONMENT.md.
|
||||
|
||||
84
scripts/check/check-provider-assets.mjs
Normal file
84
scripts/check/check-provider-assets.mjs
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env node
|
||||
import { readFile, readdir, stat } from "node:fs/promises";
|
||||
import { join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const repoRoot = fileURLToPath(new URL("../..", import.meta.url));
|
||||
const providerDir = join(repoRoot, "public", "providers");
|
||||
const MAX_RASTER_BYTES = 128 * 1024;
|
||||
const MAX_RASTER_DIMENSION = 256;
|
||||
const RASTER_EXTENSIONS = new Set([".png", ".jpg", ".jpeg"]);
|
||||
|
||||
function extensionOf(fileName) {
|
||||
const dot = fileName.lastIndexOf(".");
|
||||
return dot >= 0 ? fileName.slice(dot).toLowerCase() : "";
|
||||
}
|
||||
|
||||
function readPngDimensions(buffer) {
|
||||
if (buffer.length < 24 || buffer.toString("ascii", 1, 4) !== "PNG") return null;
|
||||
return { width: buffer.readUInt32BE(16), height: buffer.readUInt32BE(20) };
|
||||
}
|
||||
|
||||
function readJpegDimensions(buffer) {
|
||||
let offset = 2;
|
||||
while (offset + 9 < buffer.length) {
|
||||
if (buffer[offset] !== 0xff) return null;
|
||||
const marker = buffer[offset + 1];
|
||||
const length = buffer.readUInt16BE(offset + 2);
|
||||
if (marker >= 0xc0 && marker <= 0xc3) {
|
||||
return { height: buffer.readUInt16BE(offset + 5), width: buffer.readUInt16BE(offset + 7) };
|
||||
}
|
||||
offset += 2 + length;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async function readDimensions(filePath, extension) {
|
||||
const buffer = await readFile(filePath);
|
||||
if (buffer.length >= 4 && buffer.toString("ascii", 1, 4) === "PNG") {
|
||||
return readPngDimensions(buffer);
|
||||
}
|
||||
if (buffer.length >= 2 && buffer[0] === 0xff && buffer[1] === 0xd8) {
|
||||
return readJpegDimensions(buffer);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const failures = [];
|
||||
const files = await readdir(providerDir);
|
||||
|
||||
for (const fileName of files) {
|
||||
const extension = extensionOf(fileName);
|
||||
if (!RASTER_EXTENSIONS.has(extension)) continue;
|
||||
|
||||
const filePath = join(providerDir, fileName);
|
||||
const info = await stat(filePath);
|
||||
const dimensions = await readDimensions(filePath, extension);
|
||||
if (!dimensions) {
|
||||
if (info.size > 4 * 1024) {
|
||||
failures.push(`${fileName}: could not read image dimensions`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const width = dimensions.width || 0;
|
||||
const height = dimensions.height || 0;
|
||||
|
||||
if (info.size > MAX_RASTER_BYTES) {
|
||||
failures.push(
|
||||
`${fileName}: ${(info.size / 1024).toFixed(1)} KiB exceeds ${MAX_RASTER_BYTES / 1024} KiB`
|
||||
);
|
||||
}
|
||||
if (width > MAX_RASTER_DIMENSION || height > MAX_RASTER_DIMENSION) {
|
||||
failures.push(
|
||||
`${fileName}: ${width}x${height} exceeds ${MAX_RASTER_DIMENSION}px max dimension`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error("Provider asset budget failed:");
|
||||
for (const failure of failures) console.error(`- ${failure}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("Provider asset budget passed.");
|
||||
@@ -81,15 +81,15 @@ const ENV_KEY_RE = /(clientId|clientSecret|apiKey)Env\s*:/;
|
||||
//
|
||||
// 6A.8: Expanded scope to open-sse/** + src/lib/oauth/**. Newly discovered FPs:
|
||||
//
|
||||
// open-sse/services/usage.ts L546: `getMiniMaxUsage(apiKey: string, provider: "minimax" | "minimax-cn")`
|
||||
// open-sse/services/usage.ts L582: `getMiniMaxUsage(apiKey: string, provider: "minimax" | "minimax-cn")`
|
||||
// The CRED_KEY_RE matches `apiKey:` in the TypeScript function-parameter type annotation.
|
||||
// "minimax" and "minimax-cn" are provider-name strings in the type annotation, NOT credentials.
|
||||
// This is a false positive (the gate was designed for object-literal assignments, not fn params).
|
||||
// TODO(6A.8): Consider tightening CRED_KEY_RE to exclude function-signature contexts — but
|
||||
// that adds complexity; the FP rate is low (1 file). Frozen by file:line:value key.
|
||||
export const KNOWN_LITERAL_CREDS = new Set([
|
||||
"open-sse/services/usage.ts:547:minimax", // TODO(6A.8): pre-existing FP — TS fn-param type, not a credential (moved 543→547 by #3838 usage.ts comment + #4293 Codex Spark extraction)
|
||||
"open-sse/services/usage.ts:547:minimax-cn", // TODO(6A.8): pre-existing FP — TS fn-param type, not a credential (moved 543→547 by #3838 usage.ts comment + #4293 Codex Spark extraction)
|
||||
"open-sse/services/usage.ts:582:minimax", // TODO(6A.8): pre-existing FP — TS fn-param type, not a credential (moved 543→547 by #3838/#4293, then 547→582 by the v3.8.33 usage.ts growth)
|
||||
"open-sse/services/usage.ts:582:minimax-cn", // TODO(6A.8): pre-existing FP — TS fn-param type, not a credential (moved 543→547 by #3838/#4293, then 547→582 by the v3.8.33 usage.ts growth)
|
||||
]);
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user