fix: preserve logical mutation intent

This commit is contained in:
DongHyeonka
2026-08-02 01:07:19 +09:00
parent 53d181fbe4
commit cbcc7b5ed7
21 changed files with 724 additions and 96 deletions
+59
View File
@@ -0,0 +1,59 @@
export const MUTATION_INTENT_BOUNDS = Object.freeze({
intentIdMaxBytes: 256,
operationIdMaxBytes: 256,
canonicalInputIdentityMaxBytes: 16_384,
idempotencyKeyMaxBytes: 256,
} as const);
export type MutationIntent = Readonly<{
intentId: string;
operationId: string;
canonicalInputIdentity: string;
idempotencyKey?: string;
createdAtMonotonicMs: number;
}>;
const UTF8 = new TextEncoder();
function validBoundedString(value: unknown, maxBytes: number): value is string {
return (
typeof value === "string" &&
value.trim().length > 0 &&
UTF8.encode(value).byteLength <= maxBytes
);
}
export function defineMutationIntent(intent: MutationIntent): MutationIntent {
if (
!validBoundedString(
intent.intentId,
MUTATION_INTENT_BOUNDS.intentIdMaxBytes,
) ||
!validBoundedString(
intent.operationId,
MUTATION_INTENT_BOUNDS.operationIdMaxBytes,
) ||
!validBoundedString(
intent.canonicalInputIdentity,
MUTATION_INTENT_BOUNDS.canonicalInputIdentityMaxBytes,
) ||
(intent.idempotencyKey !== undefined &&
!validBoundedString(
intent.idempotencyKey,
MUTATION_INTENT_BOUNDS.idempotencyKeyMaxBytes,
)) ||
!Number.isFinite(intent.createdAtMonotonicMs) ||
intent.createdAtMonotonicMs < 0
) {
throw new TypeError("Mutation intent is invalid.");
}
return Object.freeze({
intentId: intent.intentId,
operationId: intent.operationId,
canonicalInputIdentity: intent.canonicalInputIdentity,
...(intent.idempotencyKey === undefined
? {}
: { idempotencyKey: intent.idempotencyKey }),
createdAtMonotonicMs: intent.createdAtMonotonicMs,
});
}