import type { Selectable } from 'kysely' import type * as Db from '../Db.js' import type * as db_Schema from '../Schema.js' /** Columns of the `funding_idempotency_requests` table. */ export type Table = db_Schema.FundingIdempotencyRequest /** A stored idempotency claim. */ export type Record = Selectable /** * Claims `(apiKeyId, keyHash)` for one creation attempt. A live claim rejects * mismatches, blocks pending work, resumes checkpoints, or replays completion. */ export async function claim(db: Db.Db, input: claim.Input): Promise { const now = new Date() const record: Record = { apiKeyId: input.apiKeyId, createdAt: now.toISOString(), expiresAt: new Date(now.getTime() + input.ttlMs).toISOString(), keyHash: input.keyHash, requestHash: input.requestHash, response: null, status: 'pending', transferId: null, } const inserted = await db.kysely .insertInto('funding_idempotency_requests') .values(record) .onConflict((oc) => oc.columns(['apiKeyId', 'keyHash']).doNothing()) .returningAll() .executeTakeFirst() if (inserted) return { createdAt: inserted.createdAt, type: 'claimed' } // Reclaim an expired row in place; the guard keeps two callers from both // reclaiming (only one UPDATE matches the still-expired predicate). const reclaimed = await db.kysely .updateTable('funding_idempotency_requests') .set(record) .where('apiKeyId', '=', input.apiKeyId) .where('keyHash', '=', input.keyHash) .where('expiresAt', '<=', now.toISOString()) .returningAll() .executeTakeFirst() if (reclaimed) return { createdAt: reclaimed.createdAt, type: 'claimed' } const existing = await db.kysely .selectFrom('funding_idempotency_requests') .selectAll() .where('apiKeyId', '=', input.apiKeyId) .where('keyHash', '=', input.keyHash) .executeTakeFirst() // The row vanished between the insert and the read (released claim); retry. if (!existing) return claim(db, input) if (existing.requestHash !== input.requestHash) return { type: 'mismatch' } if (existing.status === 'pending') return { type: 'pending' } if (existing.status === 'provisioned') return { createdAt: existing.createdAt, response: existing.response ?? '', type: 'resume', } return { response: existing.response ?? '', type: 'replay' } } export declare namespace claim { /** Claim identity and retention. */ type Input = { /** API key id (`key_…`) the claim is scoped to. */ apiKeyId: string /** SHA-256 of the caller Idempotency-Key. */ keyHash: string /** SHA-256 fingerprint of the canonical validated request. */ requestHash: string /** Lease duration for the pending execution, in milliseconds. */ ttlMs: number } /** Outcome of a claim attempt. */ type Result = | { createdAt: string; type: 'claimed' } | { type: 'mismatch' } | { type: 'pending' } | { response: string; type: 'replay' } | { createdAt: string; response: string; type: 'resume' } } /** Stores a provider result before committing its API resource and replay response. */ export function checkpoint(db: Db.Db, input: checkpoint.Input): Promise { const now = new Date() return db.kysely .updateTable('funding_idempotency_requests') .set({ expiresAt: new Date(now.getTime() + input.replayTtlMs).toISOString(), response: input.response, status: 'provisioned', }) .where('apiKeyId', '=', input.apiKeyId) .where('createdAt', '=', input.createdAt) .where('keyHash', '=', input.keyHash) .where('status', '=', 'pending') .returningAll() .executeTakeFirst() } export declare namespace checkpoint { /** Provider result and owned claim required for durable recovery. */ type Input = { /** API key id (`key_…`) the claim is scoped to. */ apiKeyId: string /** Creation time returned by the successful claim. */ createdAt: string /** SHA-256 of the caller Idempotency-Key. */ keyHash: string /** Recovery checkpoint retention in milliseconds. */ replayTtlMs: number /** Serialized provider result required to resume resource creation. */ response: string } } /** Completes an owned pending or provisioned claim with its replay response. */ export function complete(db: Db.Db, input: complete.Input): Promise { const now = new Date() return db.kysely .updateTable('funding_idempotency_requests') .set({ expiresAt: new Date(now.getTime() + input.replayTtlMs).toISOString(), response: input.response, status: 'completed', transferId: input.transferId ?? null, }) .where('apiKeyId', '=', input.apiKeyId) .where('createdAt', '=', input.createdAt) .where('keyHash', '=', input.keyHash) .where('status', 'in', ['pending', 'provisioned']) .returningAll() .executeTakeFirst() } export declare namespace complete { /** Completion fields. */ type Input = { /** API key id (`key_…`) the claim is scoped to. */ apiKeyId: string /** Creation time returned by the successful claim. */ createdAt: string /** SHA-256 of the caller Idempotency-Key. */ keyHash: string /** Successful-response replay retention from completion, in milliseconds. */ replayTtlMs: number /** Serialized success response replayed for the retention window. */ response: string /** Transfer id (`ftr_…`) when the request created a funding transfer. */ transferId?: string | undefined } } /** Releases a pending claim after a retryable failure. */ export async function release(db: Db.Db, input: release.Input): Promise { await db.kysely .deleteFrom('funding_idempotency_requests') .where('apiKeyId', '=', input.apiKeyId) .where('createdAt', '=', input.createdAt) .where('keyHash', '=', input.keyHash) .where('status', '=', 'pending') .execute() } export declare namespace release { /** Pending claim identity. */ type Input = { /** API key id (`key_…`) the claim is scoped to. */ apiKeyId: string /** Creation time returned by the successful claim. */ createdAt: string /** SHA-256 of the caller Idempotency-Key. */ keyHash: string } }