fix(housekeeping): harden audited command dispatch
This commit is contained in:
1 parent
6aed71a8b2
commit
796d009c07
7 files changed
+760
-109
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -1,27 +1,58 @@
|
||||
"use server";
|
||||
|
||||
import { AuditOutcomePersistenceError } from "@/features/housekeeping/foundation/commands/audit-envelope";
|
||||
import { dispatchHousekeepingCommand } from "@/features/housekeeping/foundation/commands/dispatcher";
|
||||
import { sealHousekeepingCommandRegistry } from "@/features/housekeeping/foundation/commands/registry";
|
||||
import {
|
||||
dispatchHousekeepingCommand,
|
||||
type HousekeepingCommandRequest,
|
||||
} from "@/features/housekeeping/foundation/commands/dispatcher";
|
||||
import type { HousekeepingResult } from "@/features/housekeeping/foundation/contracts";
|
||||
fail,
|
||||
type HousekeepingResult,
|
||||
mapUnknownError,
|
||||
} from "@/features/housekeeping/foundation/contracts";
|
||||
import { getHousekeepingCapabilityContext } from "@/features/housekeeping/foundation/server-capability-context";
|
||||
import { clientIp, rateLimit } from "@/lib/rate-limit";
|
||||
import { housekeepingAuditWriter } from "@/lib/services/audit";
|
||||
|
||||
export async function executeHousekeepingCommand(
|
||||
request: HousekeepingCommandRequest,
|
||||
request: unknown,
|
||||
): Promise<HousekeepingResult<unknown>> {
|
||||
sealHousekeepingCommandRegistry();
|
||||
try {
|
||||
const [context, ipAddress] = await Promise.all([
|
||||
getHousekeepingCapabilityContext(),
|
||||
clientIp(),
|
||||
]);
|
||||
|
||||
return dispatchHousekeepingCommand(request, {
|
||||
return await dispatchHousekeepingCommand(request, {
|
||||
context,
|
||||
ipAddress,
|
||||
audit: housekeepingAuditWriter,
|
||||
rateLimit: async (key, attempts, windowMs) =>
|
||||
(await rateLimit(key, attempts, windowMs)).ok,
|
||||
});
|
||||
} catch (error) {
|
||||
if (
|
||||
error instanceof AuditOutcomePersistenceError &&
|
||||
isHousekeepingResult(error.operationResult)
|
||||
) {
|
||||
return fail(
|
||||
"INTERNAL",
|
||||
"errors.housekeeping.partial",
|
||||
error.operationResult.correlationId,
|
||||
);
|
||||
}
|
||||
return mapUnknownError(error);
|
||||
}
|
||||
}
|
||||
|
||||
function isHousekeepingResult(
|
||||
value: unknown,
|
||||
): value is HousekeepingResult<unknown> {
|
||||
return (
|
||||
typeof value === "object" &&
|
||||
value !== null &&
|
||||
"ok" in value &&
|
||||
typeof (value as { ok?: unknown }).ok === "boolean" &&
|
||||
"correlationId" in value &&
|
||||
typeof (value as { correlationId?: unknown }).correlationId === "string"
|
||||
);
|
||||
}
|
||||
@@ -8,8 +8,8 @@ export interface HousekeepingCommandConfirmation {
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export function confirmHousekeepingCommand(
|
||||
command: HousekeepingCommand<unknown, unknown>,
|
||||
export function confirmHousekeepingCommand<I, O>(
|
||||
command: HousekeepingCommand<I, O>,
|
||||
reason: string | undefined,
|
||||
correlationId: string,
|
||||
): HousekeepingResult<HousekeepingCommandConfirmation> {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user