import type { TransformerSuccessHandler, WebhookPredicate } from "@flowcore/sdk-transformer-core"
const DEFAULT_TTL_MS = 60000 // 1 minute
let inMemoryCache: TTLMap
* Options for the in-memory predicate.
* @property ttlMs - The time-to-live for cache entries in milliseconds. If not specified, the default TTL is used, which is 1 minute.
export type PredicateInMemoryOptions = {
* Creates a webhook predicate checker that checks if an event ID exists in the in-memory cache.
* This function initializes the in-memory cache if it's not already initialized. It then returns a webhook predicate function that checks the existence of the event ID in the cache.
* @returns A webhook predicate function that checks the existence of the event ID in the cache.
export function createPredicateInMemoryChecker(): WebhookPredicate {
inMemoryCache = new TTLMap()
return async (eventId: string) => inMemoryCache.has(eventId)
* Creates a webhook predicate notifier that sets an event ID in the in-memory cache.
* This function initializes the in-memory cache if it's not already initialized. It then returns a webhook predicate function that sets the event ID in the cache with an optional TTL.
* @param options - The options for the in-memory predicate.
* @returns A webhook predicate function that sets the event ID in the cache.
export function createPredicateInMemoryNotifier(options?: PredicateInMemoryOptions): TransformerSuccessHandler {
inMemoryCache = new TTLMap()
return async (payload: { eventId: string }) => {
inMemoryCache.set(payload.eventId, "1", options?.ttlMs ?? DEFAULT_TTL_MS)
* Factory function for creating an in-memory predicate checker and notifier.
* This function returns an object with two methods: check and notify. The check method is a webhook predicate function that checks the existence of an event ID in the cache. The notify method is a webhook predicate function that sets an event ID in the cache.
* @param options - The options for the in-memory predicate.
* @returns An object with check and notify methods.
export function predicateinMemoryFactory(options?: PredicateInMemoryOptions) {
check: createPredicateInMemoryChecker(),
notify: createPredicateInMemoryNotifier(options),
* A map that stores key-value pairs with a time-to-live (TTL) for each entry.
* This class provides a way to store data with a limited lifetime. Each entry in the map
* can be set to expire after a specified amount of time. The map automatically removes
* Inspired by: https://gist.github.com/maman/557aa2b3b55bc971cf415c0c8369c874
private timeoutData: Record<string, Timer>
private data: Map<string, string>
private clearInstancedTimeout(key: string) {
clearTimeout(this.timeoutData[key])
delete this.timeoutData[key]
* Retrieves the value associated with a given key.
* This method returns the value stored in the map for the specified key. If the key
* does not exist or has expired, it returns undefined.
* @param key - The key for which to retrieve the value.
* @returns The value associated with the key, or undefined if the key does not exist or has expired.
return this.data.get(key)
* Checks if a key exists in the map.
* This method returns true if the specified key exists in the map and has not expired,
* otherwise it returns false.
* @param key - The key to check.
* @returns True if the key exists and has not expired, otherwise false.
return this.data.has(key)
* Sets a key-value pair in the map with an optional TTL.
* This method sets a new key-value pair in the map. If a TTL is specified, the entry
* will expire after the specified amount of time. If the key already exists, its value
* is updated and its TTL is reset.
* @param key - The key for the new entry.
* @param val - The value for the new entry.
* @param ttl - The time-to-live for the new entry in milliseconds. If not specified, the entry does not expire.
* @returns This instance of TTLMap.
set(key: string, val: string, ttl?: number) {
this.clearInstancedTimeout(key)
const timeout = setTimeout(() => {
this.clearInstancedTimeout(key)
this.timeoutData[key] = timeout
* Deletes a key-value pair from the map.
* This method removes the specified key-value pair from the map. If the key exists
* and has not expired, it returns true; otherwise, it returns false.
* @param key - The key to delete.
* @returns True if the key existed and was deleted, otherwise false.
this.clearInstancedTimeout(key)
if (this.data.has(key)) {
* Clears all key-value pairs from the map.
* This method removes all entries from the map and stops all associated timers.
for (const timeout of Object.values(this.timeoutData)) {