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
}
}