Files
openclaw/extensions/telegram/src/sticker-cache-store.ts
Peter Steinberger c23d66e3b5 refactor: consolidate coercion ownership (#122692)
* refactor: consolidate coercion ownership

* test: align shard check with weighted planning

* chore: refresh plugin SDK API baseline
2026-08-12 09:25:28 -07:00

135 lines
3.7 KiB
TypeScript

// Telegram plugin module implements sticker cache store behavior.
import type { PluginStateSyncKeyedStore } from "openclaw/plugin-sdk/plugin-state-runtime";
import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
import { getTelegramRuntime } from "./runtime.js";
import {
normalizeCachedStickerForStore,
TELEGRAM_STICKER_CACHE_MAX_ENTRIES,
TELEGRAM_STICKER_CACHE_NAMESPACE,
type CachedSticker,
} from "./sticker-cache-store.legacy-state.js";
export type { CachedSticker };
type TelegramStickerCacheStore = PluginStateSyncKeyedStore<CachedSticker>;
function openStickerCacheStore(): TelegramStickerCacheStore {
return getTelegramRuntime().state.openSyncKeyedStore<CachedSticker>({
namespace: TELEGRAM_STICKER_CACHE_NAMESPACE,
maxEntries: TELEGRAM_STICKER_CACHE_MAX_ENTRIES,
});
}
function readStickerCacheStore<T>(
operation: string,
read: (store: TelegramStickerCacheStore) => T,
fallback: T,
): T {
try {
return read(openStickerCacheStore());
} catch (err) {
logVerbose(`telegram sticker cache ${operation} failed: ${String(err)}`);
return fallback;
}
}
/**
* Get a cached sticker by its unique ID.
*/
export function getCachedSticker(fileUniqueId: string): CachedSticker | null {
return readStickerCacheStore("lookup", (store) => store.lookup(fileUniqueId) ?? null, null);
}
/**
* Add or update a sticker in the cache.
*/
export function cacheSticker(sticker: CachedSticker): void {
readStickerCacheStore(
"register",
(store) => {
store.register(sticker.fileUniqueId, normalizeCachedStickerForStore(sticker));
},
undefined,
);
}
/**
* Search cached stickers by text query (fuzzy match on description + emoji + setName).
*/
export function searchStickers(query: string, limit = 10): CachedSticker[] {
const queryLower = normalizeLowercaseStringOrEmpty(query);
const results: Array<{ sticker: CachedSticker; score: number }> = [];
for (const { value: sticker } of readStickerCacheStore(
"entries",
(store) => store.entries(),
[],
)) {
let score = 0;
const descLower = normalizeLowercaseStringOrEmpty(sticker.description);
// Exact substring match in description
if (descLower.includes(queryLower)) {
score += 10;
}
// Word-level matching
const queryWords = queryLower.split(/\s+/).filter(Boolean);
const descWords = descLower.split(/\s+/);
for (const qWord of queryWords) {
if (descWords.some((dWord) => dWord.includes(qWord))) {
score += 5;
}
}
// Emoji match
if (sticker.emoji && query.includes(sticker.emoji)) {
score += 8;
}
// Set name match
if (normalizeLowercaseStringOrEmpty(sticker.setName).includes(queryLower)) {
score += 3;
}
if (score > 0) {
results.push({ sticker, score });
}
}
return results
.toSorted((a, b) => b.score - a.score)
.slice(0, limit)
.map((r) => r.sticker);
}
/**
* Get all cached stickers (for debugging/listing).
*/
export function getAllCachedStickers(): CachedSticker[] {
return readStickerCacheStore(
"entries",
(store) => store.entries().map((entry) => entry.value),
[],
);
}
/**
* Get cache statistics.
*/
export function getCacheStats(): { count: number; oldestAt?: string; newestAt?: string } {
const stickers = getAllCachedStickers();
if (stickers.length === 0) {
return { count: 0 };
}
const sorted = [...stickers].toSorted(
(a, b) => new Date(a.cachedAt).getTime() - new Date(b.cachedAt).getTime(),
);
return {
count: stickers.length,
oldestAt: sorted[0]?.cachedAt,
newestAt: sorted[sorted.length - 1]?.cachedAt,
};
}