Compare commits

..

1 Commits

Author SHA1 Message Date
Markus Hartung
528fba953d fix(security): redact NVIDIA_API_KEY at the log sink in the ad-hoc diag script
CodeQL alert #866 (js/clear-text-logging) flagged the console.log wrapper
in nvidia-startswith-diag.ts, attributing the source to an unrelated
NOAUTH_IDS constant in tests/unit/executor-web-cookie-sweep.test.ts — no
real import/dataflow connects the two files.

The genuine risk in this script is independent of that attribution: an
upstream error or a validateProviderApiKey() result could echo the raw
NVIDIA_API_KEY back through err.stack/err.message/result, which the
script logs verbatim. The line() sink now strips any literal occurrence
of the key before it reaches the terminal, closing the clear-text-logging
class regardless of the exact taint path CodeQL reported.
2026-08-26 10:13:45 -03:00
12 changed files with 19 additions and 880 deletions

View File

@@ -1 +0,0 @@
- **fix(kie):** correct 12 more KIE Market catalog ids that were sent to `createTask` unchanged but diverge from KIE's documented upstream `model` values — GPT Image 2 T2I/I2I (drops the `gpt/` prefix), GPT Image 1.5 T2I/I2I (`gpt-image/` namespace), Seedream 5.0 Lite T2I/I2I (drops the `.0`), all 4 Flux 2 variants (`flux-2/` namespace, generic variant renamed `flex`), and Wan 2.7 Image / Image Pro (dash instead of dot) — each verified individually against the literal example request published on docs.kie.ai. `#11326`'s "everything else already matches" claim was wrong a second time (#11296); `z-image/4.0-*`/`z-image/4.5-*` and `flux/kontext` remain open, documented as unresolved in `KIE_MARKET_UPSTREAM_MODEL_IDS`'s comment pending further verification.

View File

@@ -90,19 +90,13 @@ async function resolveZaiBrowserAttachments(
> {
try {
// Browser-page upload: keep the original bytes/mimeType (no Cursor wire prep).
// EncodedImage.mimeType is optional on the wire type, but every producer
// reachable here (decodeDataUrl / fetchImageBytes) validates an image/*
// string before pushing; the fallback only satisfies the attachment type.
const images = await resolveCursorImages(imageUrls, { prepareForWire: false });
return {
attachments: images.map((image, index) => {
const mimeType = image.mimeType ?? "image/jpeg";
return {
name: zaiImageFileName(mimeType, index),
mimeType,
buffer: image.data,
};
}),
attachments: images.map((image, index) => ({
name: zaiImageFileName(image.mimeType, index),
mimeType: image.mimeType,
buffer: image.data,
})),
};
} catch (error) {
const message =

View File

@@ -92,65 +92,19 @@ interface KieImageOptions {
}
// KIE Market catalog ids are namespaced for OmniRoute's catalog
// (`<vendor>/<model>`), but the KIE Market createTask API expects
// (`google-imagen/<model>`), but the KIE Market createTask API expects
// vendor-specific upstream ids that do not follow a single consistent
// pattern. Every entry below was confirmed individually against the literal
// example request JSON published on docs.kie.ai (never inferred by pattern —
// see #11326's false "everything else already matches" claim and #11296's
// follow-up correction):
// - google-imagen: nano-banana-2 and nano-banana-pro drop the vendor
// namespace entirely; nano-banana and nano-banana-edit use a `google/`
// prefix instead of `google-imagen/` (docs.kie.ai/market/google/*).
// - gpt: gpt-image-2-* drops the `gpt/` namespace entirely
// (docs.kie.ai/market/gpt/gpt-image-2-*); gpt-image-1.5-* uses a
// `gpt-image/` namespace instead of `gpt/gpt-image-1.5-`, and keeps the
// dot in "1.5" (docs.kie.ai/market/gpt-image/1-5-*).
// - seedream: 5.0-lite-* drops the ".0" — real id is `5-lite-*`
// (docs.kie.ai/market/seedream/5-lite-text-to-image); seedream 4.5 (T2I
// and edit) already matches byte-for-byte.
// - flux: `flux/2-*` uses a `flux-2/` namespace (dash, not slash); the
// generic (non-"pro") variant is named `flex` upstream, not `2`
// (docs.kie.ai/market/flux2/pro-*, .../flex-*).
// - wan: `wan/2.7-*` keeps the dot in our catalog, but KIE's documented
// enum uses a dash — real id is `wan/2-7-*`
// (docs.kie.ai/market/wan/2-7-image[-pro]).
// - ideogram (v3-text-to-image, v3-edit, v3-remix), qwen, qwen2, and
// grok-imagine already match byte-for-byte
// (docs.kie.ai/market/{ideogram,qwen,qwen2,grok-imagine}/*).
// ideogram/v3-reframe has no dedicated docs.kie.ai page as of this sweep
// (its 3 siblings above are all direct id matches, so it is assumed
// correct by pattern, not independently confirmed).
// Two catalog entries remain UNRESOLVED after this sweep and are
// deliberately left untouched pending a follow-up (see #11296 discussion):
// - z-image/4.0-text-to-image and z-image/4.5-text-to-image: the only
// documented Z-Image Market page (docs.kie.ai/market/z-image/z-image)
// shows a single fixed `model` enum value `"z-image"` with no
// version-specific id or "version" input field found — unclear whether
// both catalog ids should collapse to the same upstream call.
// - flux/kontext: no `docs.kie.ai/market/flux2/kontext` (or similar)
// Market page exists; Flux Kontext is documented under the separate
// `/flux-kontext-api/*` docs tree with its own endpoint
// (`POST /api/v1/flux/kontext/generate`, models `flux-kontext-pro`/
// `flux-kontext-max`), not the Market `createTask` flow this map feeds.
// This entry may be miscatalogued as `isMarket: true` and need a
// dedicated reroute rather than an id rewrite.
// pattern (confirmed against docs.kie.ai/market/google/* — see #11225,
// #11296): nano-banana-2 and nano-banana-pro drop the vendor namespace
// entirely, while nano-banana and nano-banana-edit use a `google/` prefix
// instead of `google-imagen/`. Every other KIE Market namespace (seedream,
// flux, ideogram, qwen, wan, grok-imagine, gpt) already matches its real
// upstream id byte-for-byte, so this map stays scoped to google-imagen.
export const KIE_MARKET_UPSTREAM_MODEL_IDS: ReadonlyMap<string, string> = new Map([
["google-imagen/nano-banana", "google/nano-banana"],
["google-imagen/nano-banana-2", "nano-banana-2"],
["google-imagen/nano-banana-pro", "nano-banana-pro"],
["google-imagen/nano-banana-edit", "google/nano-banana-edit"],
["gpt/gpt-image-2-text-to-image", "gpt-image-2-text-to-image"],
["gpt/gpt-image-2-image-to-image", "gpt-image-2-image-to-image"],
["gpt/gpt-image-1.5-text-to-image", "gpt-image/1.5-text-to-image"],
["gpt/gpt-image-1.5-image-to-image", "gpt-image/1.5-image-to-image"],
["seedream/5.0-lite-text-to-image", "seedream/5-lite-text-to-image"],
["seedream/5.0-lite-image-to-image", "seedream/5-lite-image-to-image"],
["flux/2-pro-text-to-image", "flux-2/pro-text-to-image"],
["flux/2-pro-image-to-image", "flux-2/pro-image-to-image"],
["flux/2-text-to-image", "flux-2/flex-text-to-image"],
["flux/2-image-to-image", "flux-2/flex-image-to-image"],
["wan/2.7-image", "wan/2-7-image"],
["wan/2.7-image-pro", "wan/2-7-image-pro"],
]);
export function resolveKieMarketUpstreamModelId(publicModelId: string): string {

View File

@@ -15,7 +15,6 @@ interface ErrorResponseBody {
message: string;
type?: string;
code?: string;
reason?: string;
};
upstream_details?: Record<string, unknown> | null; // sanitized upstream provider body
}
@@ -109,7 +108,6 @@ export function sanitizeUpstreamDetails(value: unknown, depth = 0): unknown {
export type ErrorBodyClassification = {
type?: string;
code?: string;
reason?: string;
};
/**
@@ -134,7 +132,6 @@ export function buildErrorBody(
message: safeMessage,
type: classification?.type ?? errorInfo.type,
code: classification?.code ?? errorInfo.code,
reason: classification?.reason,
},
};

View File

@@ -23,7 +23,7 @@ import {
statSync,
chmodSync,
} from "node:fs";
import { join, dirname, relative } from "node:path";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { assembleStandalone } from "./assembleStandalone.mjs";
@@ -35,12 +35,6 @@ import {
APP_STAGING_REMOVAL_PATHS,
findUnexpectedArtifactPaths,
} from "./pack-artifact-policy.ts";
import {
collectWorkspaceVersions,
findPackageJsonFiles,
hasWorkspaceProtocol,
resolvePackageJsonWorkspaceProtocols,
} from "./resolveWorkspaceProtocols.ts";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
@@ -713,33 +707,6 @@ if (remainingUnexpectedFiles.length > 0) {
process.exit(1);
}
// -- Step 11: Resolve workspace: protocol dependencies -----------------
// npm/pnpm workspace protocol specifiers (workspace:*, workspace:^, ...)
// are meaningless to the npm registry and make `npm install -g omniroute`
// fail with EUNSUPPORTEDPROTOCOL. Rewrite any that leaked into published
// package.json files to the concrete workspace package version.
// Only touch files inside the staged dist/ tree; workspace member source
// package.json files must never be mutated by the publish step.
const workspaceVersions = collectWorkspaceVersions(ROOT);
const publishablePackageJsonDirs = [DIST_DIR];
const publishablePackageJsonPaths = publishablePackageJsonDirs
.flatMap((dir) => (existsSync(dir) ? findPackageJsonFiles(dir) : []))
.filter((filePath) => existsSync(filePath));
for (const pkgJsonPath of publishablePackageJsonPaths) {
let pkg: Record<string, unknown>;
try {
pkg = JSON.parse(readFileSync(pkgJsonPath, "utf8")) as Record<string, unknown>;
} catch {
continue;
}
if (!hasWorkspaceProtocol(pkg)) continue;
const resolved = resolvePackageJsonWorkspaceProtocols(pkg, workspaceVersions);
writeFileSync(pkgJsonPath, JSON.stringify(resolved, null, 2) + "\n");
console.log(` [resolved] Resolved workspace: protocols in ${relative(ROOT, pkgJsonPath)}`);
}
// ── Done ───────────────────────────────────────────────────
const distPkg = join(DIST_DIR, "package.json");
if (existsSync(distPkg)) {

View File

@@ -1,228 +0,0 @@
/**
* Resolve pnpm/npm workspace protocol dependencies to concrete semver versions.
*
* The npm registry clients cannot parse `workspace:` specifiers. During prepublish
* we rewrite any `workspace:*`, `workspace:^`, `workspace:~` (or explicit
* `workspace:<range>`) dependency declarations to the matching workspace package's
* actual version before npm pack/publish sees them.
*/
import { readFileSync, readdirSync, statSync } from "node:fs";
import { join } from "node:path";
import * as yaml from "js-yaml";
const WORKSPACE_PROTOCOL_RE = /^workspace:/;
const DEPENDENCY_FIELDS = [
"dependencies",
"devDependencies",
"peerDependencies",
"optionalDependencies",
] as const;
/**
* Parse a simple workspace glob entry into concrete directories relative to a root.
* Supports entries like "packages/*" and literal directory names like "open-sse".
*/
function expandWorkspaceEntry(root: string, entry: string): string[] {
const trimmed = entry.trim();
if (!trimmed) return [];
if (!trimmed.endsWith("/*")) {
const dir = join(root, trimmed);
try {
return statSync(dir).isDirectory() ? [dir] : [];
} catch {
return [];
}
}
const parent = join(root, trimmed.slice(0, -2));
let entries: string[] = [];
try {
entries = readdirSync(parent);
} catch {
return [];
}
return entries
.map((name) => join(parent, name))
.filter((dir) => {
try {
return statSync(dir).isDirectory();
} catch {
return false;
}
});
}
/**
* Read the root package.json and, if present, pnpm-workspace.yaml to discover
* workspace member directories. Returns a map of package name -> version.
*/
export function collectWorkspaceVersions(projectRoot: string): Map<string, string> {
const versions = new Map<string, string>();
const rootPkgPath = join(projectRoot, "package.json");
let workspaceEntries: string[] = [];
try {
const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf8")) as {
workspaces?: string[];
};
if (Array.isArray(rootPkg.workspaces)) {
workspaceEntries.push(...rootPkg.workspaces);
}
} catch {
// ignore unreadable root package.json
}
const pnpmWorkspacePath = join(projectRoot, "pnpm-workspace.yaml");
try {
const yamlContent = readFileSync(pnpmWorkspacePath, "utf8");
const doc = yaml.load(yamlContent) as { packages?: unknown } | null | undefined;
if (doc && Array.isArray(doc.packages)) {
for (const entry of doc.packages) {
if (typeof entry === "string" && entry) {
workspaceEntries.push(entry);
}
}
}
} catch {
// ignore missing or malformed pnpm-workspace.yaml
}
const seenDirs = new Set<string>();
for (const entry of workspaceEntries) {
for (const dir of expandWorkspaceEntry(projectRoot, entry)) {
if (seenDirs.has(dir)) continue;
seenDirs.add(dir);
try {
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
name?: string;
version?: string;
};
if (pkg.name && pkg.version) {
versions.set(pkg.name, pkg.version);
}
} catch {
// skip unreadable workspace member package.json
}
}
}
return versions;
}
/**
* Resolve workspace protocol dependencies inside a package.json object.
*
* Replaces `workspace:*`, `workspace:^`, `workspace:~`, `workspace:<range>`,
* and `workspace:<packageName>` with the concrete version of the referenced
* workspace package. Throws if a workspace specifier cannot be resolved.
*/
export function resolvePackageJsonWorkspaceProtocols(
pkg: Record<string, unknown>,
workspaceVersions: Map<string, string>
): Record<string, unknown> {
const resolved: Record<string, unknown> = { ...pkg };
for (const field of DEPENDENCY_FIELDS) {
const deps = pkg[field];
if (!deps || typeof deps !== "object" || Array.isArray(deps)) continue;
const resolvedDeps: Record<string, string> = {};
let changed = false;
for (const [depName, versionSpec] of Object.entries(deps as Record<string, unknown>)) {
if (typeof versionSpec !== "string") {
resolvedDeps[depName] = String(versionSpec ?? "");
continue;
}
if (!WORKSPACE_PROTOCOL_RE.test(versionSpec)) {
resolvedDeps[depName] = versionSpec;
continue;
}
const body = versionSpec.slice("workspace:".length);
let concrete: string | undefined;
if (body === "*") {
concrete = workspaceVersions.get(depName);
} else if (body === "^") {
const version = workspaceVersions.get(depName);
concrete = version ? `^${version}` : undefined;
} else if (body === "~") {
const version = workspaceVersions.get(depName);
concrete = version ? `~${version}` : undefined;
} else if (body.startsWith("^") || body.startsWith("~") || /^[\d<>=]/.test(body)) {
// Explicit range inside workspace: protocol - strip the protocol prefix.
concrete = body;
} else {
// workspace:<packageName> - resolve to that package's version.
concrete = workspaceVersions.get(body);
}
if (concrete) {
resolvedDeps[depName] = concrete;
changed = true;
} else {
throw new Error(
`Cannot resolve workspace protocol "${versionSpec}" for dependency "${depName}". ` +
"Make sure the referenced package is a declared workspace member with a version."
);
}
}
if (changed) {
resolved[field] = resolvedDeps;
}
}
return resolved;
}
/**
* Return true if any dependency field in the package contains a workspace: specifier.
*/
export function hasWorkspaceProtocol(pkg: Record<string, unknown>): boolean {
for (const field of DEPENDENCY_FIELDS) {
const deps = pkg[field];
if (!deps || typeof deps !== "object" || Array.isArray(deps)) continue;
for (const versionSpec of Object.values(deps as Record<string, unknown>)) {
if (typeof versionSpec === "string" && WORKSPACE_PROTOCOL_RE.test(versionSpec)) {
return true;
}
}
}
return false;
}
/**
* Recursively walk a directory and return every package.json path found.
* Stops descending after maxDepth to avoid runaway recursion on deep trees.
*/
export function findPackageJsonFiles(dir: string, maxDepth = 10): string[] {
const results: string[] = [];
if (maxDepth < 0) return results;
let entries: string[] = [];
try {
entries = readdirSync(dir);
} catch {
return results;
}
for (const entry of entries) {
if (entry === "node_modules") continue;
const fullPath = join(dir, entry);
let stat;
try {
stat = statSync(fullPath);
} catch {
continue;
}
if (stat.isDirectory()) {
results.push(...findPackageJsonFiles(fullPath, maxDepth - 1));
} else if (entry === "package.json") {
results.push(fullPath);
}
}
return results;
}

View File

@@ -66,8 +66,8 @@ export function structuralRejectionResponse(status: 413 | 503, maxMessages: numb
{
type: historyLimit ? "payload_too_large" : "server_error",
code: historyLimit ? "chat_history_too_large" : "chat_admission_busy",
reason: historyLimit ? "message_limit" : "structure_limit",
}
);
body.error.reason = historyLimit ? "message_limit" : "structure_limit";
return new Response(JSON.stringify(body), { status, headers });
}

View File

@@ -1,269 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import {
collectWorkspaceVersions,
resolvePackageJsonWorkspaceProtocols,
hasWorkspaceProtocol,
findPackageJsonFiles,
} from "../../../scripts/build/resolveWorkspaceProtocols.ts";
function tmpDir(prefix: string): string {
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
}
function writeJson(filePath: string, data: unknown): void {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
}
function readJson(filePath: string): Record<string, unknown> {
return JSON.parse(fs.readFileSync(filePath, "utf8")) as Record<string, unknown>;
}
test("resolvePackageJsonWorkspaceProtocols replaces workspace:*, workspace:^, workspace:~", () => {
const versions = new Map([
["@omniroute/open-sse", "3.8.51"],
["@omniroute/shared", "1.2.3"],
]);
const resolved = resolvePackageJsonWorkspaceProtocols(
{
name: "omniroute",
version: "3.8.51",
dependencies: {
"@omniroute/open-sse": "workspace:^",
"@omniroute/shared": "workspace:*",
lodash: "^4.17.0",
},
devDependencies: {
"@omniroute/open-sse": "workspace:~",
},
peerDependencies: {
"@omniroute/shared": "workspace:1.2.3",
},
optionalDependencies: {
"@omniroute/open-sse": "workspace:>=3.0.0",
},
},
versions
);
assert.equal((resolved.dependencies as Record<string, string>)["@omniroute/open-sse"], "^3.8.51");
assert.equal((resolved.dependencies as Record<string, string>)["@omniroute/shared"], "1.2.3");
assert.equal((resolved.dependencies as Record<string, string>).lodash, "^4.17.0");
assert.equal(
(resolved.devDependencies as Record<string, string>)["@omniroute/open-sse"],
"~3.8.51"
);
assert.equal((resolved.peerDependencies as Record<string, string>)["@omniroute/shared"], "1.2.3");
assert.equal(
(resolved.optionalDependencies as Record<string, string>)["@omniroute/open-sse"],
">=3.0.0"
);
});
test("resolvePackageJsonWorkspaceProtocols leaves non-workspace specs untouched", () => {
const resolved = resolvePackageJsonWorkspaceProtocols(
{
name: "x",
dependencies: {
a: "^1.0.0",
b: "file:../b",
c: "npm:alias@1.0.0",
},
},
new Map()
);
assert.equal((resolved.dependencies as Record<string, string>).a, "^1.0.0");
assert.equal((resolved.dependencies as Record<string, string>).b, "file:../b");
assert.equal((resolved.dependencies as Record<string, string>).c, "npm:alias@1.0.0");
assert.equal(hasWorkspaceProtocol(resolved), false);
});
test("resolvePackageJsonWorkspaceProtocols throws for unresolvable workspace protocol", () => {
assert.throws(
() =>
resolvePackageJsonWorkspaceProtocols(
{
name: "x",
dependencies: {
"@missing/pkg": "workspace:^",
},
},
new Map()
),
/Cannot resolve workspace protocol/
);
});
test("collectWorkspaceVersions reads npm workspaces and pnpm-workspace.yaml", () => {
const root = tmpDir("workspace-versions-");
writeJson(path.join(root, "package.json"), {
name: "root",
version: "0.0.0",
workspaces: ["packages/*", "open-sse"],
});
fs.mkdirSync(path.join(root, "packages", "a"), { recursive: true });
writeJson(path.join(root, "packages", "a", "package.json"), {
name: "@scope/a",
version: "1.0.0",
});
fs.mkdirSync(path.join(root, "open-sse"), { recursive: true });
writeJson(path.join(root, "open-sse", "package.json"), {
name: "@scope/open-sse",
version: "2.0.0",
});
// pnpm-workspace.yaml adds an extra directory not in npm workspaces.
fs.mkdirSync(path.join(root, "packages", "b"), { recursive: true });
writeJson(path.join(root, "packages", "b", "package.json"), {
name: "@scope/b",
version: "3.0.0",
});
fs.writeFileSync(path.join(root, "pnpm-workspace.yaml"), "packages:\n - 'packages/*'\n");
const versions = collectWorkspaceVersions(root);
assert.equal(versions.get("@scope/a"), "1.0.0");
assert.equal(versions.get("@scope/open-sse"), "2.0.0");
assert.equal(versions.get("@scope/b"), "3.0.0");
});
test("findPackageJsonFiles skips node_modules and respects maxDepth", () => {
const root = tmpDir("pkg-json-files-");
fs.mkdirSync(path.join(root, "a"), { recursive: true });
writeJson(path.join(root, "a", "package.json"), {});
fs.mkdirSync(path.join(root, "node_modules", "x"), { recursive: true });
writeJson(path.join(root, "node_modules", "x", "package.json"), {});
const files = findPackageJsonFiles(root);
assert.equal(files.length, 1);
assert.ok(files[0].endsWith(path.join("a", "package.json")));
// Build a deep tree and confirm maxDepth bounds the walk.
const deep = tmpDir("pkg-json-deep-");
let current = deep;
for (let i = 0; i < 12; i += 1) {
current = path.join(current, `level${i}`);
fs.mkdirSync(current, { recursive: true });
}
writeJson(path.join(current, "package.json"), {});
assert.equal(findPackageJsonFiles(deep, 10).length, 0);
assert.equal(findPackageJsonFiles(deep, 12).length, 1);
});
test("collectWorkspaceVersions parses pnpm-workspace.yaml with js-yaml", () => {
const root = tmpDir("pnpm-yaml-");
writeJson(path.join(root, "package.json"), { name: "root", version: "0.0.0" });
// Flow-style array, nested quotes, comments inside the packages list, and an
// unrelated top-level key before packages are all valid YAML that the old line
// scanner could not handle.
fs.writeFileSync(
path.join(root, "pnpm-workspace.yaml"),
"preferWorkspacePackages: true\n" +
"packages:\n" +
' - "packages/*"\n' +
" - 'apps/*'\n" +
" # comment inside the list\n" +
" - open-sse\n"
);
fs.mkdirSync(path.join(root, "packages", "a"), { recursive: true });
writeJson(path.join(root, "packages", "a", "package.json"), {
name: "@scope/a",
version: "1.0.0",
});
fs.mkdirSync(path.join(root, "apps", "web"), { recursive: true });
writeJson(path.join(root, "apps", "web", "package.json"), {
name: "@scope/web",
version: "2.0.0",
});
fs.mkdirSync(path.join(root, "open-sse"), { recursive: true });
writeJson(path.join(root, "open-sse", "package.json"), {
name: "@scope/open-sse",
version: "3.0.0",
});
const versions = collectWorkspaceVersions(root);
assert.equal(versions.get("@scope/a"), "1.0.0");
assert.equal(versions.get("@scope/web"), "2.0.0");
assert.equal(versions.get("@scope/open-sse"), "3.0.0");
});
test("prepublish Step 11 fixture resolves workspace: protocols in dist package.json files", () => {
const root = tmpDir("prepublish-step11-");
const distDir = path.join(root, "dist");
// Workspace member source files contain a workspace: specifier (simulating the
// monorepo source). They must NOT be mutated by the publish step.
fs.mkdirSync(path.join(root, "packages", "shared"), { recursive: true });
const sourcePkgPath = path.join(root, "packages", "shared", "package.json");
writeJson(sourcePkgPath, {
name: "@scope/shared",
version: "1.2.3",
dependencies: {
"@scope/other": "workspace:*",
},
});
fs.mkdirSync(path.join(root, "packages", "other"), { recursive: true });
writeJson(path.join(root, "packages", "other", "package.json"), {
name: "@scope/other",
version: "4.5.6",
});
writeJson(path.join(root, "package.json"), {
name: "root",
version: "0.0.0",
workspaces: ["packages/*"],
});
// The staged dist/ package.json contains workspace: specifiers that leaked
// into the publish artifact and must be rewritten to concrete versions.
fs.mkdirSync(distDir, { recursive: true });
const distPkgPath = path.join(distDir, "package.json");
writeJson(distPkgPath, {
name: "omniroute",
version: "3.8.51",
dependencies: {
"@scope/shared": "workspace:^",
"@scope/other": "workspace:*",
lodash: "^4.17.0",
},
});
// This is the same logic prepublish.ts Step 11 runs, scoped to the fixture.
const workspaceVersions = collectWorkspaceVersions(root);
const publishablePackageJsonPaths = findPackageJsonFiles(distDir).filter((filePath) =>
fs.existsSync(filePath)
);
for (const pkgJsonPath of publishablePackageJsonPaths) {
const pkg = readJson(pkgJsonPath);
if (!hasWorkspaceProtocol(pkg)) continue;
const resolved = resolvePackageJsonWorkspaceProtocols(pkg, workspaceVersions);
fs.writeFileSync(pkgJsonPath, JSON.stringify(resolved, null, 2) + "\n");
}
// dist/package.json must have concrete versions.
const distPkg = readJson(distPkgPath);
assert.equal((distPkg.dependencies as Record<string, string>)["@scope/shared"], "^1.2.3");
assert.equal((distPkg.dependencies as Record<string, string>)["@scope/other"], "4.5.6");
assert.equal((distPkg.dependencies as Record<string, string>).lodash, "^4.17.0");
assert.equal(hasWorkspaceProtocol(distPkg), false);
// Source package.json must remain untouched.
const sourcePkg = readJson(sourcePkgPath);
assert.equal((sourcePkg.dependencies as Record<string, string>)["@scope/other"], "workspace:*");
});

View File

@@ -1,35 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
structuralRejectionResponse,
} from "../../src/shared/middleware/chatAdmissionResponses.ts";
// Pins the machine-readable error.reason contract of the chat admission
// structural rejections (#TS2339 regression guard): buildErrorBody now owns
// the reason field via ErrorBodyClassification, so the response bodies keep
// carrying it without post-construction mutation of an untyped field.
test("structuralRejectionResponse 413 carries reason=message_limit classification", () => {
const res = structuralRejectionResponse(413, 40);
assert.equal(res.status, 413);
assert.ok(!res.headers.has("Retry-After"), "413 is not retryable-by-header");
return res.text().then((raw) => {
const body = JSON.parse(raw);
assert.equal(body.error.reason, "message_limit");
assert.equal(body.error.type, "payload_too_large");
assert.equal(body.error.code, "chat_history_too_large");
assert.ok(!body.error.message.includes("at /"), "must not leak stack traces");
});
});
test("structuralRejectionResponse 503 carries reason=structure_limit and Retry-After", () => {
const res = structuralRejectionResponse(503, 40);
assert.equal(res.status, 503);
assert.equal(res.headers.get("Retry-After"), "1");
return res.text().then((raw) => {
const body = JSON.parse(raw);
assert.equal(body.error.reason, "structure_limit");
assert.equal(body.error.type, "server_error");
assert.equal(body.error.code, "chat_admission_busy");
});
});

View File

@@ -1,88 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
process.env.DATA_DIR = mkdtempSync(join(tmpdir(), "omniroute-kie-11296-probe-"));
const { handleImageGeneration } = await import(
"../../open-sse/handlers/imageGeneration.ts"
);
interface CapturedCreate {
url: string;
body: Record<string, unknown>;
}
async function captureCreateTaskModel(publicModel: string): Promise<string> {
const originalFetch = globalThis.fetch;
let captured: CapturedCreate | undefined;
globalThis.fetch = (async (url: unknown, options: { body?: unknown } = {}) => {
const stringUrl = String(url);
if (stringUrl === "https://api.kie.ai/api/v1/jobs/createTask") {
captured = {
url: stringUrl,
body: JSON.parse(String(options.body ?? "{}")) as Record<string, unknown>,
};
return new Response(JSON.stringify({ code: 200, data: { taskId: "kie-probe-task-1" } }), {
status: 200,
headers: { "content-type": "application/json" },
});
}
if (stringUrl.startsWith("https://api.kie.ai/api/v1/jobs/recordInfo")) {
return new Response(
JSON.stringify({
code: 200,
data: {
state: "success",
resultJson: JSON.stringify({ resultUrls: ["https://example.com/kie-probe.png"] }),
},
}),
{ status: 200, headers: { "content-type": "application/json" } }
);
}
throw new Error(`Unexpected URL: ${stringUrl}`);
}) as typeof globalThis.fetch;
try {
await handleImageGeneration({
body: { model: publicModel, prompt: "probe prompt", size: "1024x1024", n: 1 },
credentials: { apiKey: "test-kie-key" },
log: null,
});
assert.ok(captured, "expected a createTask request to be captured");
return String(captured.body.model);
} finally {
globalThis.fetch = originalFetch;
}
}
test("#11296: GPT Image 2 T2I sends KIE's real upstream id (no namespace prefix)", async () => {
const sentModel = await captureCreateTaskModel("kie/gpt/gpt-image-2-text-to-image");
assert.equal(sentModel, "gpt-image-2-text-to-image");
});
test("#11296: GPT Image 2 I2I sends KIE's real upstream id (no namespace prefix)", async () => {
const sentModel = await captureCreateTaskModel("kie/gpt/gpt-image-2-image-to-image");
assert.equal(sentModel, "gpt-image-2-image-to-image");
});
test("#11296: GPT Image 1.5 T2I sends KIE's real 'gpt-image/' namespace", async () => {
const sentModel = await captureCreateTaskModel("kie/gpt/gpt-image-1.5-text-to-image");
assert.equal(sentModel, "gpt-image/1.5-text-to-image");
});
test("#11296: Seedream 5.0 Lite T2I sends KIE's real id without the '.0'", async () => {
const sentModel = await captureCreateTaskModel("kie/seedream/5.0-lite-text-to-image");
assert.equal(sentModel, "seedream/5-lite-text-to-image");
});
test("#11296: Flux 2 Pro T2I sends KIE's real 'flux-2/' namespace (dash, not slash)", async () => {
const sentModel = await captureCreateTaskModel("kie/flux/2-pro-text-to-image");
assert.equal(sentModel, "flux-2/pro-text-to-image");
});

View File

@@ -103,21 +103,13 @@ function resolveLiveKieMarketCatalog() {
}));
}
test("KIE Market resolver changes exactly the documented mismatched ids in the live market catalog", () => {
test("KIE Market resolver changes exactly the 4 google-imagen ids in the live market catalog", () => {
const roundTrips = resolveLiveKieMarketCatalog();
const changed = roundTrips.filter(({ publicModelId, upstreamModelId }) => {
return upstreamModelId !== publicModelId;
});
assert.deepEqual(changed, [
{
publicModelId: "seedream/5.0-lite-text-to-image",
upstreamModelId: "seedream/5-lite-text-to-image",
},
{
publicModelId: "seedream/5.0-lite-image-to-image",
upstreamModelId: "seedream/5-lite-image-to-image",
},
{
publicModelId: "google-imagen/nano-banana-2",
upstreamModelId: "nano-banana-2",
@@ -134,71 +126,19 @@ test("KIE Market resolver changes exactly the documented mismatched ids in the l
publicModelId: "google-imagen/nano-banana-edit",
upstreamModelId: "google/nano-banana-edit",
},
{
publicModelId: "flux/2-pro-image-to-image",
upstreamModelId: "flux-2/pro-image-to-image",
},
{
publicModelId: "flux/2-pro-text-to-image",
upstreamModelId: "flux-2/pro-text-to-image",
},
{
publicModelId: "flux/2-image-to-image",
upstreamModelId: "flux-2/flex-image-to-image",
},
{
publicModelId: "flux/2-text-to-image",
upstreamModelId: "flux-2/flex-text-to-image",
},
{
publicModelId: "gpt/gpt-image-1.5-text-to-image",
upstreamModelId: "gpt-image/1.5-text-to-image",
},
{
publicModelId: "gpt/gpt-image-1.5-image-to-image",
upstreamModelId: "gpt-image/1.5-image-to-image",
},
{
publicModelId: "gpt/gpt-image-2-text-to-image",
upstreamModelId: "gpt-image-2-text-to-image",
},
{
publicModelId: "gpt/gpt-image-2-image-to-image",
upstreamModelId: "gpt-image-2-image-to-image",
},
{
publicModelId: "wan/2.7-image",
upstreamModelId: "wan/2-7-image",
},
{
publicModelId: "wan/2.7-image-pro",
upstreamModelId: "wan/2-7-image-pro",
},
]);
});
const REWRITTEN_MARKET_IDS = new Set([
const REWRITTEN_GOOGLE_IMAGEN_MARKET_IDS = new Set([
"google-imagen/nano-banana",
"google-imagen/nano-banana-2",
"google-imagen/nano-banana-pro",
"google-imagen/nano-banana-edit",
"gpt/gpt-image-2-text-to-image",
"gpt/gpt-image-2-image-to-image",
"gpt/gpt-image-1.5-text-to-image",
"gpt/gpt-image-1.5-image-to-image",
"seedream/5.0-lite-text-to-image",
"seedream/5.0-lite-image-to-image",
"flux/2-pro-text-to-image",
"flux/2-pro-image-to-image",
"flux/2-text-to-image",
"flux/2-image-to-image",
"wan/2.7-image",
"wan/2.7-image-pro",
]);
test("KIE Market resolver preserves every other live market catalog id byte-identically", () => {
for (const { publicModelId, upstreamModelId } of resolveLiveKieMarketCatalog()) {
if (!REWRITTEN_MARKET_IDS.has(publicModelId)) {
if (!REWRITTEN_GOOGLE_IMAGEN_MARKET_IDS.has(publicModelId)) {
assert.equal(
upstreamModelId,
publicModelId,
@@ -208,8 +148,8 @@ test("KIE Market resolver preserves every other live market catalog id byte-iden
}
});
test("KIE Market resolver keeps exactly the explicit upstream id mappings (#11296)", () => {
assert.equal(KIE_MARKET_UPSTREAM_MODEL_IDS.size, 16);
test("KIE Market resolver keeps exactly the explicit google-imagen upstream id mappings (#11296)", () => {
assert.equal(KIE_MARKET_UPSTREAM_MODEL_IDS.size, 4);
});
test("KIE Market resolver passes an unknown namespaced id through byte-identically", () => {
@@ -269,78 +209,6 @@ test("KIE Market createTask sends the KIE upstream id for Nano Banana Edit (#112
);
});
test("KIE Market createTask sends the unprefixed upstream id for GPT Image 2 T2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/gpt/gpt-image-2-text-to-image");
assert.equal(captured.create.body.model, "gpt-image-2-text-to-image");
});
test("KIE Market createTask sends the unprefixed upstream id for GPT Image 2 I2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/gpt/gpt-image-2-image-to-image");
assert.equal(captured.create.body.model, "gpt-image-2-image-to-image");
});
test("KIE Market createTask sends the 'gpt-image/' namespace for GPT Image 1.5 T2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/gpt/gpt-image-1.5-text-to-image");
assert.equal(captured.create.body.model, "gpt-image/1.5-text-to-image");
});
test("KIE Market createTask sends the 'gpt-image/' namespace for GPT Image 1.5 I2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/gpt/gpt-image-1.5-image-to-image");
assert.equal(captured.create.body.model, "gpt-image/1.5-image-to-image");
});
test("KIE Market createTask drops the '.0' for Seedream 5.0 Lite T2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/seedream/5.0-lite-text-to-image");
assert.equal(captured.create.body.model, "seedream/5-lite-text-to-image");
});
test("KIE Market createTask drops the '.0' for Seedream 5.0 Lite I2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/seedream/5.0-lite-image-to-image");
assert.equal(captured.create.body.model, "seedream/5-lite-image-to-image");
});
test("KIE Market createTask sends the 'flux-2/' namespace for Flux 2 Pro T2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/flux/2-pro-text-to-image");
assert.equal(captured.create.body.model, "flux-2/pro-text-to-image");
});
test("KIE Market createTask sends the 'flux-2/' namespace for Flux 2 Pro I2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/flux/2-pro-image-to-image");
assert.equal(captured.create.body.model, "flux-2/pro-image-to-image");
});
test("KIE Market createTask sends the 'flux-2/flex-' name for Flux 2 T2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/flux/2-text-to-image");
assert.equal(captured.create.body.model, "flux-2/flex-text-to-image");
});
test("KIE Market createTask sends the 'flux-2/flex-' name for Flux 2 I2I (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/flux/2-image-to-image");
assert.equal(captured.create.body.model, "flux-2/flex-image-to-image");
});
test("KIE Market createTask sends the dash-separated id for Wan 2.7 Image (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/wan/2.7-image");
assert.equal(captured.create.body.model, "wan/2-7-image");
});
test("KIE Market createTask sends the dash-separated id for Wan 2.7 Image Pro (#11296)", async () => {
const captured = await runKieMarketGeneration("kie/wan/2.7-image-pro");
assert.equal(captured.create.body.model, "wan/2-7-image-pro");
});
test("KIE Market createTask leaves genuinely namespaced upstream ids untouched (#11225 control)", async () => {
const captured = await runKieMarketGeneration("kie/seedream/4.5-text-to-image");

View File

@@ -1,20 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import { resolveCursorImages } from "../../open-sse/utils/cursorImages.ts";
// zai-web maps resolveCursorImages() output into browser-upload attachments
// whose mimeType is REQUIRED. EncodedImage.mimeType is optional on the wire
// type, so zai-web carries an `?? "image/jpeg"` fallback — this test pins the
// producer contract that makes the fallback dead code in practice: every
// image that reaches a browser upload must arrive with a concrete image/*
// mime string (decodeDataUrl / fetchImageBytes validate it before pushing).
const PIXEL_PNG =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==";
test("resolveCursorImages (prepareForWire:false) always yields a concrete image/* mimeType", async () => {
const images = await resolveCursorImages([PIXEL_PNG], { prepareForWire: false });
assert.equal(images.length, 1);
assert.equal(typeof images[0]!.mimeType, "string");
assert.match(images[0]!.mimeType as string, /^image\//);
});