完成40%

This commit is contained in:
rain
2026-07-23 17:21:27 +08:00
parent f1edc6b533
commit bb6431b319
114 changed files with 10931 additions and 877 deletions
+66
View File
@@ -0,0 +1,66 @@
const DEFAULT_COOLDOWN_SECONDS = 60;
const sceneExpiresAt = new Map();
const requireFunction = (value, name) => {
if (typeof value !== "function") {
throw new TypeError(`${name} must be a function`);
}
return value;
};
export const createAuthSmsCooldown = ({
sceneCode,
onChange,
now = Date.now,
setIntervalFn = setInterval,
clearIntervalFn = clearInterval,
}) => {
if (typeof sceneCode !== "string" || !sceneCode.trim()) {
throw new TypeError("sceneCode must be a non-empty string");
}
const normalizedSceneCode = sceneCode.trim();
const publish = requireFunction(onChange, "onChange");
const readNow = requireFunction(now, "now");
const scheduleInterval = requireFunction(setIntervalFn, "setIntervalFn");
const cancelInterval = requireFunction(clearIntervalFn, "clearIntervalFn");
let timer = null;
const stopTimer = () => {
if (timer === null) return;
cancelInterval(timer);
timer = null;
};
const sync = () => {
const expiresAt = sceneExpiresAt.get(normalizedSceneCode) || 0;
const remaining = Math.max(
0,
Math.ceil((expiresAt - Number(readNow())) / 1000),
);
if (remaining === 0) {
sceneExpiresAt.delete(normalizedSceneCode);
stopTimer();
} else if (timer === null) {
timer = scheduleInterval(sync, 1000);
}
publish(remaining);
return remaining;
};
const start = (seconds = DEFAULT_COOLDOWN_SECONDS) => {
if (!Number.isInteger(seconds) || seconds < 1 || seconds > 300) {
throw new TypeError("cooldown seconds must be an integer from 1 to 300");
}
sceneExpiresAt.set(
normalizedSceneCode,
Number(readNow()) + seconds * 1000,
);
return sync();
};
return Object.freeze({
start,
sync,
dispose: stopTimer,
});
};