Redeeming an invite read uses_count, checked the cap in JS, then did a non-atomic uses_count = uses_count + 1 write AFTER creating the membership. Two concurrent redemptions of a max_uses=1 invite both passed the check and both created a member, and the counter under-counted. Fix: claim a use ATOMICALLY before creating the membership via a compare-and-swap on uses_count (lib/invite-claim.ts) — the UPDATE only writes when uses_count still equals the value the cap decision was based on, so of two racing claims exactly one wins. The loser re-reads and retries while capacity remains (multi-use invites unaffected). On a failed membership insert the claim is rolled back so a slot is not burned. Extracted to lib/invite-claim.ts (out of the 'use server' surface, unit-tested). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7 lines
247 B
TypeScript
7 lines
247 B
TypeScript
/// <reference types="next" />
|
|
/// <reference types="next/image-types/global" />
|
|
import "./.next/types/routes.d.ts";
|
|
|
|
// NOTE: This file should not be edited
|
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|