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:
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user