chore: normalize formatting (2-space → tabs) in stream-error-patterns files

Re-tab only — no logic changes. Follows the repo's tab-based formatting
for these files, matching the CommandCode executor/translator style.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
2026-08-05 09:03:41 +07:00
parent e2f8323ab1
commit 2a37a4085e
8 changed files with 929 additions and 529 deletions

View File

@@ -447,9 +447,7 @@ export default function ProviderDetailPage() {
);
// Load per-provider stream error patterns (one per line)
setStreamErrorPatternsText(
((settingsData.streamErrorPatterns || {})[providerId] || []).join(
"\n",
),
((settingsData.streamErrorPatterns || {})[providerId] || []).join("\n"),
);
const autoPingSettingsKey = AUTO_PING_SETTINGS_KEYS[providerId];
const apCfg = autoPingSettingsKey
@@ -2495,9 +2493,9 @@ export default function ProviderDetailPage() {
<div className="mb-3">
<h2 className="text-lg font-semibold">Stream Error Patterns</h2>
<p className="mt-1 text-sm text-text-muted">
Treat HTTP-200 streams whose first bytes match one of these
patterns as failed requests (enables fallback + FAILED logs). One
pattern per line: plain text (case-insensitive substring) or{" "}
Treat HTTP-200 streams whose first bytes match one of these patterns
as failed requests (enables fallback + FAILED logs). One pattern per
line: plain text (case-insensitive substring) or{" "}
<code className="rounded bg-background px-1 py-0.5 font-mono text-xs">
/regex/flags
</code>

View File

@@ -2,117 +2,118 @@ import { getAdapter } from "../driver.js";
import { parseJson, stringifyJson } from "../helpers/jsonCol.js";
const DEFAULT_MITM_ROUTER_BASE = "http://localhost:20128";
const DEFAULT_HEADROOM_URL = process.env.HEADROOM_URL || "http://localhost:8787";
const DEFAULT_HEADROOM_URL =
process.env.HEADROOM_URL || "http://localhost:8787";
const DEFAULT_SETTINGS = {
cloudEnabled: false,
tunnelEnabled: false,
tunnelUrl: "",
tunnelProvider: "cloudflare",
tailscaleEnabled: false,
tailscaleUrl: "",
stickyRoundRobinLimit: 3,
providerStrategies: {},
providerTimeouts: {},
streamErrorPatterns: {},
defaultTimeoutMs: null,
quotaVisibility: {},
comboStrategy: "fallback",
comboStickyRoundRobinLimit: 1,
comboStrategies: {},
requireLogin: true,
tunnelDashboardAccess: true,
authMode: "password",
oidcIssuerUrl: "",
oidcClientId: "",
oidcClientSecret: "",
oidcScopes: "openid profile email",
oidcLoginLabel: "Sign in with OIDC",
enableObservability: true,
observabilityMaxRecords: 1000,
observabilityBatchSize: 20,
observabilityFlushIntervalMs: 5000,
observabilityMaxJsonSize: 5,
outboundProxyEnabled: false,
outboundProxyUrl: "",
outboundNoProxy: "",
mitmRouterBaseUrl: DEFAULT_MITM_ROUTER_BASE,
dnsToolEnabled: {},
rtkEnabled: true,
headroomEnabled: false,
headroomUrl: DEFAULT_HEADROOM_URL,
headroomCompressUserMessages: false,
cavemanEnabled: false,
cavemanLevel: "full",
ponytailEnabled: false,
ponytailLevel: "full",
pxpipeEnabled: false,
pxpipeAutoInstall: true,
pxpipeMinChars: 25000,
pxpipeTimeoutMs: 15000,
cloudEnabled: false,
tunnelEnabled: false,
tunnelUrl: "",
tunnelProvider: "cloudflare",
tailscaleEnabled: false,
tailscaleUrl: "",
stickyRoundRobinLimit: 3,
providerStrategies: {},
providerTimeouts: {},
streamErrorPatterns: {},
defaultTimeoutMs: null,
quotaVisibility: {},
comboStrategy: "fallback",
comboStickyRoundRobinLimit: 1,
comboStrategies: {},
requireLogin: true,
tunnelDashboardAccess: true,
authMode: "password",
oidcIssuerUrl: "",
oidcClientId: "",
oidcClientSecret: "",
oidcScopes: "openid profile email",
oidcLoginLabel: "Sign in with OIDC",
enableObservability: true,
observabilityMaxRecords: 1000,
observabilityBatchSize: 20,
observabilityFlushIntervalMs: 5000,
observabilityMaxJsonSize: 5,
outboundProxyEnabled: false,
outboundProxyUrl: "",
outboundNoProxy: "",
mitmRouterBaseUrl: DEFAULT_MITM_ROUTER_BASE,
dnsToolEnabled: {},
rtkEnabled: true,
headroomEnabled: false,
headroomUrl: DEFAULT_HEADROOM_URL,
headroomCompressUserMessages: false,
cavemanEnabled: false,
cavemanLevel: "full",
ponytailEnabled: false,
ponytailLevel: "full",
pxpipeEnabled: false,
pxpipeAutoInstall: true,
pxpipeMinChars: 25000,
pxpipeTimeoutMs: 15000,
};
async function readRaw() {
const db = await getAdapter();
const row = db.get(`SELECT data FROM settings WHERE id = 1`);
return row ? parseJson(row.data, {}) : {};
const db = await getAdapter();
const row = db.get(`SELECT data FROM settings WHERE id = 1`);
return row ? parseJson(row.data, {}) : {};
}
// Merge raw settings with defaults; backward-compat for missing keys
function mergeWithDefaults(raw) {
const merged = { ...DEFAULT_SETTINGS, ...(raw || {}) };
for (const [key, defVal] of Object.entries(DEFAULT_SETTINGS)) {
if (merged[key] === undefined) {
if (
key === "outboundProxyEnabled" &&
typeof merged.outboundProxyUrl === "string" &&
merged.outboundProxyUrl.trim()
) {
merged[key] = true;
} else {
merged[key] = defVal;
}
}
}
return merged;
const merged = { ...DEFAULT_SETTINGS, ...(raw || {}) };
for (const [key, defVal] of Object.entries(DEFAULT_SETTINGS)) {
if (merged[key] === undefined) {
if (
key === "outboundProxyEnabled" &&
typeof merged.outboundProxyUrl === "string" &&
merged.outboundProxyUrl.trim()
) {
merged[key] = true;
} else {
merged[key] = defVal;
}
}
}
return merged;
}
export async function getSettings() {
const raw = await readRaw();
return mergeWithDefaults(raw);
const raw = await readRaw();
return mergeWithDefaults(raw);
}
// Atomic read-merge-write inside transaction (prevents losing concurrent updates)
export async function updateSettings(updates) {
const db = await getAdapter();
let next;
db.transaction(() => {
const row = db.get(`SELECT data FROM settings WHERE id = 1`);
const current = row ? parseJson(row.data, {}) : {};
next = { ...current, ...updates };
db.run(
`INSERT INTO settings(id, data) VALUES(1, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`,
[stringifyJson(next)]
);
});
return mergeWithDefaults(next);
const db = await getAdapter();
let next;
db.transaction(() => {
const row = db.get(`SELECT data FROM settings WHERE id = 1`);
const current = row ? parseJson(row.data, {}) : {};
next = { ...current, ...updates };
db.run(
`INSERT INTO settings(id, data) VALUES(1, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`,
[stringifyJson(next)],
);
});
return mergeWithDefaults(next);
}
export async function isCloudEnabled() {
const settings = await getSettings();
return settings.cloudEnabled === true;
const settings = await getSettings();
return settings.cloudEnabled === true;
}
export async function getCloudUrl() {
const settings = await getSettings();
return (
settings.cloudUrl ||
process.env.CLOUD_URL ||
process.env.NEXT_PUBLIC_CLOUD_URL ||
""
);
const settings = await getSettings();
return (
settings.cloudUrl ||
process.env.CLOUD_URL ||
process.env.NEXT_PUBLIC_CLOUD_URL ||
""
);
}
export async function exportSettings() {
return await readRaw();
return await readRaw();
}