merge: sync dev changes

This commit is contained in:
ajnart committed 2026-07-28 23:45:19 +02:00
commit 92a2be2b65
21 files changed
+2332 -985

No files matched your search

+20 -4
View File
@@ -30,8 +30,15 @@ const settleIntegrationQueriesInternal = async <TIntegration extends Integration
options?: Options<TIntegration, TResult>,
): Promise<IntegrationQuerySettlement<TResult>> => {
const settled = await Promise.allSettled(integrations.map(async (integration) => fn(integration)));
const results = settled.flatMap((result, index) => {
if (result.status === "fulfilled") return [result.value];
const results: TResult[] = [];
const errors: unknown[] = [];
settled.forEach((result, index) => {
if (result.status === "fulfilled") {
results.push(result.value);
return;
}
const integration = integrations[index];
logger.warn(
new ErrorWithMetadata(
@@ -40,8 +47,13 @@ const settleIntegrationQueriesInternal = async <TIntegration extends Integration
{ cause: result.reason },
),
);
if (options?.fallback && integration) return [options.fallback(integration, result.reason)];
return [];
if (options?.fallback && integration) {
results.push(options.fallback(integration, result.reason));
return;
}
errors.push(result.reason);
});
const firstFailure = settled.find((result) => result.status === "rejected");
@@ -54,6 +66,10 @@ const settleIntegrationQueriesInternal = async <TIntegration extends Integration
throw firstFailure.reason;
}
if (options?.throwOnAllFailure !== false && results.length === 0 && errors.length > 0) {
throw errors[0];
}
return {
results,
failedIntegrationCount: settled.filter((result) => result.status === "rejected").length,
@@ -0,0 +1,50 @@
import { describe, expect, test, vi } from "vitest";
import { settleIntegrationQueries } from "../settle-integrations";
const mocks = vi.hoisted(() => ({
logger: { warn: vi.fn() },
}));
vi.mock("@homarr/core/infrastructure/logs", () => ({
createLogger: () => mocks.logger,
}));
vi.mock("@homarr/core/infrastructure/logs/error", () => ({
ErrorWithMetadata: Error,
}));
const integrations = [
{ id: "first", name: "First", kind: "plex" },
{ id: "second", name: "Second", kind: "jellyfin" },
];
describe("settleIntegrationQueries", () => {
test("returns an empty result when no integrations are configured", async () => {
await expect(settleIntegrationQueries([], vi.fn())).resolves.toEqual([]);
});
test("keeps successful integrations when another integration fails", async () => {
const error = new Error("Plex unavailable");
await expect(
settleIntegrationQueries(integrations, (integration) =>
integration.id === "first" ? Promise.reject(error) : Promise.resolve(integration.name),
),
).resolves.toEqual(["Second"]);
});
test("rejects when every integration fails", async () => {
const error = new Error("Integration unavailable");
await expect(settleIntegrationQueries(integrations, () => Promise.reject(error))).rejects.toBe(error);
});
test("uses configured fallbacks when every integration fails", async () => {
await expect(
settleIntegrationQueries(integrations, () => Promise.reject(new Error("Integration unavailable")), {
fallback: (integration) => integration.name,
}),
).resolves.toEqual(["First", "Second"]);
});
});