snapshot_poker_phase3

This commit is contained in:
DeSqBlocki
2026-09-08 19:37:02 +02:00
parent 995a2317b9
commit 903a2f3081
25 changed files with 7457 additions and 60 deletions
+247
View File
@@ -268,6 +268,251 @@ async function changeCookies(
}
/*
* ============================================================
* IDEMPOTENT COOKIE CHANGE
* ============================================================
*
* Applies a Cookie mutation at most once for a user-scoped
* operationId. This is useful for persistent game buy-ins and
* cash-outs that may be retried after a crash or restart.
*
* The Cookie balance mutation and operation marker are written
* atomically to the same user document.
*/
async function changeCookiesOnce(
userId,
amount,
operationId
) {
if (
!Number.isSafeInteger(
amount
)
) {
throw new Error(
"INVALID_COOKIE_AMOUNT"
);
}
if (
typeof operationId !==
"string"
||
!/^[A-Za-z0-9:_-]{1,160}$/.test(
operationId
)
) {
throw new Error(
"INVALID_COOKIE_OPERATION_ID"
);
}
if (
amount ===
0
) {
return {
applied:
false,
balance:
await getCookieBalance(
userId
)
};
}
const {
cookies
} =
getCollections();
const filter = {
userId,
appliedCookieOperations: {
$ne:
operationId
}
};
if (
amount <
0
) {
filter.cookies = {
$gte:
Math.abs(
amount
)
};
}
const update = {
$inc: {
cookies:
amount
},
$addToSet: {
appliedCookieOperations:
operationId
}
};
if (
amount >
0
) {
update.$setOnInsert = {
userId
};
}
try {
const result =
await cookies.updateOne(
filter,
update,
{
upsert:
amount > 0
}
);
if (
result.modifiedCount ===
1
||
result.upsertedCount ===
1
) {
return {
applied:
true,
balance:
await getCookieBalance(
userId
)
};
}
}
catch (error) {
/*
* A concurrent positive retry can race an upsert.
* The unique userId index may reject the losing insert.
* Re-read below and treat an already-recorded operation
* as a successful idempotent retry.
*/
if (
error?.code !==
11000
) {
throw error;
}
}
const document =
await cookies.findOne(
{
userId
},
{
projection: {
cookies:
1,
appliedCookieOperations:
1
}
}
);
const operations =
Array.isArray(
document
?.appliedCookieOperations
)
? document
.appliedCookieOperations
: [];
if (
operations.includes(
operationId
)
) {
return {
applied:
false,
balance:
Math.max(
0,
Number(
document?.cookies ??
0
)
)
};
}
if (
amount <
0
) {
throw new Error(
"INSUFFICIENT_COOKIES"
);
}
throw new Error(
"COOKIE_OPERATION_FAILED"
);
}
async function hasCookieOperation(
userId,
operationId
) {
if (
typeof operationId !==
"string"
||
!/^[A-Za-z0-9:_-]{1,160}$/.test(
operationId
)
) {
throw new Error(
"INVALID_COOKIE_OPERATION_ID"
);
}
const {
cookies
} =
getCollections();
const document =
await cookies.findOne(
{
userId,
appliedCookieOperations:
operationId
},
{
projection: {
_id:
1
}
}
);
return Boolean(
document
);
}
/*
* ============================================================
* COOKIE TRANSFER
@@ -1188,6 +1433,8 @@ module.exports = {
getCookieBalance,
changeCookies,
changeCookiesOnce,
hasCookieOperation,
transferCookies,
getCooldown,