@levrbet/shared 0.4.58 → 0.4.60

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,3 +4,4 @@ export * from "./game.query.engine";
4
4
  export * from "./leagues.cache.service";
5
5
  export * from "./game.progress";
6
6
  export * from "./market.query.engine";
7
+ export * from "./pending.cancellation.service";
@@ -20,4 +20,5 @@ __exportStar(require("./game.query.engine"), exports);
20
20
  __exportStar(require("./leagues.cache.service"), exports);
21
21
  __exportStar(require("./game.progress"), exports);
22
22
  __exportStar(require("./market.query.engine"), exports);
23
+ __exportStar(require("./pending.cancellation.service"), exports);
23
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/oracle/redis-cache-manager/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAkC;AAClC,6CAA0B;AAC1B,sDAAmC;AACnC,0DAAuC;AACvC,kDAA+B;AAC/B,wDAAqC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/oracle/redis-cache-manager/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAkC;AAClC,6CAA0B;AAC1B,sDAAmC;AACnC,0DAAuC;AACvC,kDAA+B;AAC/B,wDAAqC;AACrC,iEAA8C"}
@@ -0,0 +1,31 @@
1
+ import Redis from "ioredis";
2
+ export declare const PENDING_CANCELLATION_KEY_PREFIX = "pending_cancellation";
3
+ /** Redis TTL for cleanup — extended well beyond the admin window so expired entries
4
+ * can still be scanned and auto-processed by the monitor endpoint. */
5
+ export declare const PENDING_CANCELLATION_REDIS_TTL_SECONDS: number;
6
+ /** Admin review window: 6 hours from the moment the entry is created. */
7
+ export declare const PENDING_CANCELLATION_WINDOW_MS: number;
8
+ export interface PendingCancellationEntry {
9
+ gameObjectId: string;
10
+ gameId: number;
11
+ chainId: number;
12
+ provider: "lsports" | "optic_odds";
13
+ providerStatus: string;
14
+ gameClock: string | null;
15
+ gamePeriod: number | undefined;
16
+ /** Raw provider event snapshot that triggered the cancellation. */
17
+ providerEvent: Record<string, unknown>;
18
+ markedAt: number;
19
+ expiresAt: number;
20
+ }
21
+ /** Writes a pending-cancellation entry to Redis for a game, unless one already exists. */
22
+ export declare const markGameForPendingCancellation: (redis: Redis, entry: Omit<PendingCancellationEntry, "markedAt" | "expiresAt">) => Promise<{
23
+ created: boolean;
24
+ }>;
25
+ export declare const getPendingCancellation: (redis: Redis, gameObjectId: string) => Promise<PendingCancellationEntry | null>;
26
+ export declare const deletePendingCancellation: (redis: Redis, gameObjectId: string) => Promise<void>;
27
+ export declare const isGamePendingCancellation: (redis: Redis, gameObjectId: string) => Promise<boolean>;
28
+ /** Scans all pending-cancellation entries whose 4-hour admin window has already expired. */
29
+ export declare const scanExpiredPendingCancellations: (redis: Redis) => Promise<PendingCancellationEntry[]>;
30
+ /** Scans ALL pending-cancellation entries regardless of expiry status. */
31
+ export declare const scanAllPendingCancellations: (redis: Redis) => Promise<PendingCancellationEntry[]>;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scanAllPendingCancellations = exports.scanExpiredPendingCancellations = exports.isGamePendingCancellation = exports.deletePendingCancellation = exports.getPendingCancellation = exports.markGameForPendingCancellation = exports.PENDING_CANCELLATION_WINDOW_MS = exports.PENDING_CANCELLATION_REDIS_TTL_SECONDS = exports.PENDING_CANCELLATION_KEY_PREFIX = void 0;
4
+ exports.PENDING_CANCELLATION_KEY_PREFIX = "pending_cancellation";
5
+ /** Redis TTL for cleanup — extended well beyond the admin window so expired entries
6
+ * can still be scanned and auto-processed by the monitor endpoint. */
7
+ exports.PENDING_CANCELLATION_REDIS_TTL_SECONDS = 48 * 60 * 60; // 48 h
8
+ /** Admin review window: 6 hours from the moment the entry is created. */
9
+ exports.PENDING_CANCELLATION_WINDOW_MS = 6 * 60 * 60 * 1000;
10
+ const pendingCancellationKey = (gameObjectId) => `${exports.PENDING_CANCELLATION_KEY_PREFIX}:${gameObjectId}`;
11
+ /** Writes a pending-cancellation entry to Redis for a game, unless one already exists. */
12
+ const markGameForPendingCancellation = async (redis, entry) => {
13
+ const key = pendingCancellationKey(entry.gameObjectId);
14
+ const now = Date.now();
15
+ const full = {
16
+ ...entry,
17
+ markedAt: now,
18
+ expiresAt: now + exports.PENDING_CANCELLATION_WINDOW_MS,
19
+ };
20
+ // NX — only set if the key does not already exist (avoid overwriting active admin review)
21
+ const result = await redis.set(key, JSON.stringify(full), "EX", exports.PENDING_CANCELLATION_REDIS_TTL_SECONDS, "NX");
22
+ return { created: result === "OK" };
23
+ };
24
+ exports.markGameForPendingCancellation = markGameForPendingCancellation;
25
+ const getPendingCancellation = async (redis, gameObjectId) => {
26
+ const raw = await redis.get(pendingCancellationKey(gameObjectId));
27
+ if (!raw)
28
+ return null;
29
+ return JSON.parse(raw);
30
+ };
31
+ exports.getPendingCancellation = getPendingCancellation;
32
+ const deletePendingCancellation = async (redis, gameObjectId) => {
33
+ await redis.del(pendingCancellationKey(gameObjectId));
34
+ };
35
+ exports.deletePendingCancellation = deletePendingCancellation;
36
+ const isGamePendingCancellation = async (redis, gameObjectId) => {
37
+ const exists = await redis.exists(pendingCancellationKey(gameObjectId));
38
+ return exists === 1;
39
+ };
40
+ exports.isGamePendingCancellation = isGamePendingCancellation;
41
+ /** Scans all pending-cancellation entries whose 4-hour admin window has already expired. */
42
+ const scanExpiredPendingCancellations = async (redis) => {
43
+ const keys = [];
44
+ let cursor = "0";
45
+ do {
46
+ const [nextCursor, batchKeys] = await redis.scan(cursor, "MATCH", `${exports.PENDING_CANCELLATION_KEY_PREFIX}:*`, "COUNT", 100);
47
+ cursor = nextCursor;
48
+ keys.push(...batchKeys);
49
+ } while (cursor !== "0");
50
+ if (keys.length === 0)
51
+ return [];
52
+ const raw = await redis.mget(...keys);
53
+ const now = Date.now();
54
+ const expired = [];
55
+ for (const val of raw) {
56
+ if (!val)
57
+ continue;
58
+ try {
59
+ const entry = JSON.parse(val);
60
+ if (entry.expiresAt <= now) {
61
+ expired.push(entry);
62
+ }
63
+ }
64
+ catch {
65
+ // skip malformed entries
66
+ }
67
+ }
68
+ return expired;
69
+ };
70
+ exports.scanExpiredPendingCancellations = scanExpiredPendingCancellations;
71
+ /** Scans ALL pending-cancellation entries regardless of expiry status. */
72
+ const scanAllPendingCancellations = async (redis) => {
73
+ const keys = [];
74
+ let cursor = "0";
75
+ do {
76
+ const [nextCursor, batchKeys] = await redis.scan(cursor, "MATCH", `${exports.PENDING_CANCELLATION_KEY_PREFIX}:*`, "COUNT", 100);
77
+ cursor = nextCursor;
78
+ keys.push(...batchKeys);
79
+ } while (cursor !== "0");
80
+ if (keys.length === 0)
81
+ return [];
82
+ const raw = await redis.mget(...keys);
83
+ const entries = [];
84
+ for (const val of raw) {
85
+ if (!val)
86
+ continue;
87
+ try {
88
+ entries.push(JSON.parse(val));
89
+ }
90
+ catch {
91
+ // skip malformed entries
92
+ }
93
+ }
94
+ return entries;
95
+ };
96
+ exports.scanAllPendingCancellations = scanAllPendingCancellations;
97
+ //# sourceMappingURL=pending.cancellation.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending.cancellation.service.js","sourceRoot":"","sources":["../../../../src/server/oracle/redis-cache-manager/pending.cancellation.service.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levrbet/shared",
3
- "version": "0.4.58",
3
+ "version": "0.4.60",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {