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 ); } /** * N-06. The single idempotency-key authority shared by the V2 compatibility * client and the V3 executor. * * A caller-supplied value is never trimmed, regenerated or silently dropped: * an invalid key is a contract violation, because replaying a keyed command * without its key is exactly the unsafe behaviour the key exists to prevent. */ export function isValidIdempotencyKey(value: unknown): value is string { if ( !validBoundedString( value, MUTATION_INTENT_BOUNDS.idempotencyKeyMaxBytes, ) ) { return false; } for (const character of value) { const codePoint = character.codePointAt(0) ?? 0; if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) { return false; } } return true; } export function defineIdempotencyKey(value: unknown): string { if (!isValidIdempotencyKey(value)) { throw new TypeError("Idempotency key is invalid."); } return value; } 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, ) || // OPT-NET-02. Intent definition and executor admission share one key // authority; a second, looser rule here is how a control character reaches // an `Idempotency-Key` header. (intent.idempotencyKey !== undefined && !isValidIdempotencyKey(intent.idempotencyKey)) || !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, }); }