mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(resilience): expose providerCooldown in GET+PATCH /api/resilience (#3590)
This commit is contained in:
committed by
GitHub
parent
39f7be320d
commit
7d7a45ae28
@@ -133,6 +133,7 @@ export async function GET() {
|
||||
maxRetries: resilience.waitForCooldown.maxRetries,
|
||||
maxRetryWaitSec: resilience.waitForCooldown.maxRetryWaitSec,
|
||||
},
|
||||
providerCooldown: resilience.providerCooldown,
|
||||
legacy: buildLegacyResilienceCompat(resilience),
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
@@ -188,6 +189,12 @@ export async function PATCH(request) {
|
||||
...(body.waitForCooldown
|
||||
? { waitForCooldown: body.waitForCooldown as ResilienceSettingsPatch["waitForCooldown"] }
|
||||
: {}),
|
||||
...(body.providerCooldown
|
||||
? {
|
||||
providerCooldown:
|
||||
body.providerCooldown as ResilienceSettingsPatch["providerCooldown"],
|
||||
}
|
||||
: {}),
|
||||
...normalizeLegacyPatch(body),
|
||||
});
|
||||
|
||||
@@ -222,6 +229,7 @@ export async function PATCH(request) {
|
||||
maxRetries: nextResilience.waitForCooldown.maxRetries,
|
||||
maxRetryWaitSec: nextResilience.waitForCooldown.maxRetryWaitSec,
|
||||
},
|
||||
providerCooldown: nextResilience.providerCooldown,
|
||||
legacy: buildLegacyResilienceCompat(nextResilience),
|
||||
});
|
||||
} catch (err: unknown) {
|
||||
|
||||
@@ -1161,6 +1161,14 @@ const waitForCooldownSettingsSchema = z
|
||||
})
|
||||
.strict();
|
||||
|
||||
const providerCooldownSettingsSchema = z
|
||||
.object({
|
||||
enabled: z.boolean().optional(),
|
||||
minRetryCooldownMs: z.number().int().min(0).max(300000).optional(),
|
||||
maxRetryCooldownMs: z.number().int().min(0).max(3600000).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const updateResilienceSchema = z
|
||||
.object({
|
||||
requestQueue: requestQueueSettingsSchema.optional(),
|
||||
@@ -1179,6 +1187,7 @@ export const updateResilienceSchema = z
|
||||
.strict()
|
||||
.optional(),
|
||||
waitForCooldown: waitForCooldownSettingsSchema.optional(),
|
||||
providerCooldown: providerCooldownSettingsSchema.optional(),
|
||||
profiles: z
|
||||
.object({
|
||||
oauth: legacyResilienceProfileSchema.optional(),
|
||||
@@ -1195,6 +1204,7 @@ export const updateResilienceSchema = z
|
||||
!value.connectionCooldown &&
|
||||
!value.providerBreaker &&
|
||||
!value.waitForCooldown &&
|
||||
!value.providerCooldown &&
|
||||
!value.profiles &&
|
||||
!value.defaults
|
||||
) {
|
||||
|
||||
65
tests/unit/resilience-provider-cooldown-api-3556.test.ts
Normal file
65
tests/unit/resilience-provider-cooldown-api-3556.test.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Regression test for #3556 / fix: providerCooldown missing from GET+PATCH /api/resilience
|
||||
*
|
||||
* The ResilienceTab component fetches GET /api/resilience and expects a `providerCooldown`
|
||||
* field; likewise PATCH must accept and persist it. Without both, the Settings → Resilience
|
||||
* page crashes on load and cannot save the provider-cooldown configuration.
|
||||
*/
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
// Validate the schema accepts providerCooldown
|
||||
import { updateResilienceSchema } from "../../src/shared/validation/schemas.js";
|
||||
// Validate settings roundtrip
|
||||
import {
|
||||
resolveResilienceSettings,
|
||||
mergeResilienceSettings,
|
||||
} from "../../src/lib/resilience/settings.js";
|
||||
|
||||
describe("providerCooldown in updateResilienceSchema", () => {
|
||||
it("accepts a valid providerCooldown patch", () => {
|
||||
const result = updateResilienceSchema.safeParse({
|
||||
providerCooldown: {
|
||||
enabled: true,
|
||||
minRetryCooldownMs: 3000,
|
||||
maxRetryCooldownMs: 120000,
|
||||
},
|
||||
});
|
||||
assert.equal(result.success, true, `Schema rejected valid patch: ${JSON.stringify(result)}`);
|
||||
});
|
||||
|
||||
it("accepts partial providerCooldown patch", () => {
|
||||
const result = updateResilienceSchema.safeParse({
|
||||
providerCooldown: { enabled: false },
|
||||
});
|
||||
assert.equal(result.success, true, `Schema rejected partial patch: ${JSON.stringify(result)}`);
|
||||
});
|
||||
|
||||
it("rejects unknown keys inside providerCooldown", () => {
|
||||
const result = updateResilienceSchema.safeParse({
|
||||
providerCooldown: { enabled: true, unknownKey: 42 },
|
||||
});
|
||||
assert.equal(result.success, false, "Schema should reject unknown keys");
|
||||
});
|
||||
});
|
||||
|
||||
describe("providerCooldown roundtrip through mergeResilienceSettings", () => {
|
||||
it("merges providerCooldown overrides correctly", () => {
|
||||
const base = resolveResilienceSettings({});
|
||||
const merged = mergeResilienceSettings(base, {
|
||||
providerCooldown: { enabled: true, minRetryCooldownMs: 2000 },
|
||||
});
|
||||
assert.equal(merged.providerCooldown.enabled, true);
|
||||
assert.equal(merged.providerCooldown.minRetryCooldownMs, 2000);
|
||||
// maxRetryCooldownMs should remain from default
|
||||
assert.ok(merged.providerCooldown.maxRetryCooldownMs > 0);
|
||||
});
|
||||
|
||||
it("resolveResilienceSettings returns providerCooldown field", () => {
|
||||
const settings = resolveResilienceSettings({});
|
||||
assert.ok("providerCooldown" in settings, "providerCooldown missing from resolved settings");
|
||||
assert.ok("enabled" in settings.providerCooldown);
|
||||
assert.ok("minRetryCooldownMs" in settings.providerCooldown);
|
||||
assert.ok("maxRetryCooldownMs" in settings.providerCooldown);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user