openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
72 lines (71 loc) • 1.98 kB
JavaScript
import crypto from "node:crypto";
//#region src/shared/one-time-ticket-store.ts
function createOneTimeTicketStore(opts) {
const now = opts.now ?? (() => Date.now());
const entries = /* @__PURE__ */ new Map();
const remove = (token) => {
const entry = entries.get(token);
if (entry) {
entries.delete(token);
clearTimeout(entry.timer);
entry.revokeSignal?.removeEventListener("abort", entry.onRevoke);
}
return entry;
};
const expire = (token) => {
const entry = remove(token);
if (entry) opts.onExpire?.(entry.payload, token);
};
return {
mint(payload, options = {}) {
const token = crypto.randomBytes(24).toString("hex");
const ttlMs = options.ttlMs ?? opts.ttlMs;
const expiresAtMs = (options.nowMs ?? now()) + ttlMs;
const timer = setTimeout(() => expire(token), ttlMs);
timer.unref?.();
const { revokeSignal } = options;
const onRevoke = () => {
remove(token);
};
entries.set(token, {
payload,
expiresAtMs,
timer,
revokeSignal,
onRevoke
});
revokeSignal?.addEventListener("abort", onRevoke, { once: true });
if (revokeSignal?.aborted) remove(token);
return {
token,
expiresAtMs
};
},
consume(token, nowMs, accept) {
const currentTimeMs = nowMs ?? now();
const normalized = token.trim();
if (!/^[a-f0-9]{48}$/u.test(normalized)) return;
if (accept) {
const pending = entries.get(normalized);
if (pending && pending.expiresAtMs > currentTimeMs && (!accept(pending.payload) || entries.get(normalized) !== pending)) return;
}
const entry = remove(normalized);
if (entry && entry.expiresAtMs <= currentTimeMs) {
opts.onExpire?.(entry.payload, normalized);
return;
}
return entry?.payload;
},
delete(token) {
return remove(token) !== void 0;
},
clear() {
for (const token of entries.keys()) expire(token);
},
get size() {
return entries.size;
}
};
}
//#endregion
export { createOneTimeTicketStore as t };