|
| 1 | +import { |
| 2 | +asDateTimestampMs, |
| 3 | +resolveExpiresAtMsFromDurationMs, |
| 4 | +} from "openclaw/plugin-sdk/number-runtime"; |
1 | 5 | import { fetchGraphJson, type GraphResponse } from "./graph.js"; |
2 | 6 | |
3 | 7 | export type GraphThreadMessage = { |
@@ -14,6 +18,13 @@ export type GraphThreadMessage = {
|
14 | 18 | const teamGroupIdCache = new Map<string, { groupId: string; expiresAt: number }>(); |
15 | 19 | const CACHE_TTL_MS = 10 * 60 * 1000; // 10 minutes |
16 | 20 | |
| 21 | +function resolveTeamGroupIdCacheExpiresAt(nowRaw = Date.now()): number | undefined { |
| 22 | +const now = asDateTimestampMs(nowRaw); |
| 23 | +return now === undefined |
| 24 | + ? undefined |
| 25 | + : resolveExpiresAtMsFromDurationMs(CACHE_TTL_MS, { nowMs: now }); |
| 26 | +} |
| 27 | + |
17 | 28 | /** |
18 | 29 | * Strip HTML tags from Teams message content, preserving @mention display names. |
19 | 30 | * Teams wraps mentions in <at>Name</at> tags. |
@@ -44,8 +55,13 @@ export async function resolveTeamGroupId(
|
44 | 55 | conversationTeamId: string, |
45 | 56 | ): Promise<string> { |
46 | 57 | const cached = teamGroupIdCache.get(conversationTeamId); |
47 | | -if (cached && cached.expiresAt > Date.now()) { |
48 | | -return cached.groupId; |
| 58 | +if (cached) { |
| 59 | +const now = asDateTimestampMs(Date.now()); |
| 60 | +const expiresAt = asDateTimestampMs(cached.expiresAt); |
| 61 | +if (now !== undefined && expiresAt !== undefined && expiresAt > now) { |
| 62 | +return cached.groupId; |
| 63 | +} |
| 64 | +teamGroupIdCache.delete(conversationTeamId); |
49 | 65 | } |
50 | 66 | |
51 | 67 | // The team ID in channelData is typically the group ID itself for standard teams. |
@@ -59,10 +75,13 @@ export async function resolveTeamGroupId(
|
59 | 75 | // Only cache when the Graph lookup succeeds — caching a fallback raw ID |
60 | 76 | // can cause silent failures for the entire TTL if the ID is not a valid |
61 | 77 | // Graph team GUID (e.g. Bot Framework conversation key). |
62 | | -teamGroupIdCache.set(conversationTeamId, { |
63 | | - groupId, |
64 | | -expiresAt: Date.now() + CACHE_TTL_MS, |
65 | | -}); |
| 78 | +const expiresAt = resolveTeamGroupIdCacheExpiresAt(); |
| 79 | +if (expiresAt !== undefined) { |
| 80 | +teamGroupIdCache.set(conversationTeamId, { |
| 81 | + groupId, |
| 82 | + expiresAt, |
| 83 | +}); |
| 84 | +} |
66 | 85 | |
67 | 86 | return groupId; |
68 | 87 | } catch { |
|