From 746ab4ff553b763b9daa98ae85b93fb1453e8278 Mon Sep 17 00:00:00 2001 From: mfbz Date: Mon, 26 May 2025 11:22:41 +0200 Subject: [PATCH 1/2] Refactored legacy events file --- packages/fcl-core/src/events/legacy-events.js | 91 ----------------- packages/fcl-core/src/events/legacy-events.ts | 97 +++++++++++++++++++ 2 files changed, 97 insertions(+), 91 deletions(-) delete mode 100644 packages/fcl-core/src/events/legacy-events.js create mode 100644 packages/fcl-core/src/events/legacy-events.ts diff --git a/packages/fcl-core/src/events/legacy-events.js b/packages/fcl-core/src/events/legacy-events.js deleted file mode 100644 index 0a7fba8b7..000000000 --- a/packages/fcl-core/src/events/legacy-events.js +++ /dev/null @@ -1,91 +0,0 @@ -import {spawn, subscriber, SUBSCRIBE, UNSUBSCRIBE} from "@onflow/util-actor" -import { - config, - block, - getEventsAtBlockHeightRange, - send, - decode, -} from "@onflow/sdk" - -const RATE = 10000 -const UPDATED = "UPDATED" -const TICK = "TICK" -const HIGH_WATER_MARK = "hwm" - -const scheduleTick = async ctx => { - return setTimeout( - () => ctx.sendSelf(TICK), - await config().get("fcl.eventPollRate", RATE) - ) -} - -const HANDLERS = { - [TICK]: async ctx => { - if (!ctx.hasSubs()) return - let hwm = ctx.get(HIGH_WATER_MARK) - if (hwm == null) { - ctx.put(HIGH_WATER_MARK, await block()) - ctx.put(TICK, await scheduleTick(ctx)) - } else { - let next = await block() - ctx.put(HIGH_WATER_MARK, next) - if (hwm.height < next.height) { - const data = await send([ - getEventsAtBlockHeightRange(ctx.self(), hwm.height + 1, next.height), - ]).then(decode) - for (let d of data) ctx.broadcast(UPDATED, d) - } - ctx.put(TICK, await scheduleTick(ctx)) - } - }, - [SUBSCRIBE]: async (ctx, letter) => { - if (!ctx.hasSubs()) { - ctx.put(TICK, await scheduleTick(ctx)) - } - ctx.subscribe(letter.from) - }, - [UNSUBSCRIBE]: (ctx, letter) => { - ctx.unsubscribe(letter.from) - if (!ctx.hasSubs()) { - clearTimeout(ctx.get(TICK)) - ctx.delete(TICK) - ctx.delete(HIGH_WATER_MARK) - } - }, -} - -const spawnEvents = key => spawn(HANDLERS, key) - -/** - * @typedef {import("@onflow/typedefs").Event} Event - */ - -/** - * @typedef {object} SubscribeObject - * @property {Function} subscribe - The subscribe function. - */ - -/** - * @callback SubscriptionCallback - * @returns {Event} - */ - -/** - * @description - Subscribe to events - * @param {string} key - A valid event name - * @returns {SubscribeObject} - * - * @example - * import * as fcl from "@onflow/fcl" - * fcl.events(eventName).subscribe((event) => console.log(event)) - */ -export function events(key) { - return { - /** - * @description - Subscribe to events - * @param {Function} callback - The callback function - * @returns {SubscriptionCallback} - */ - subscribe: callback => subscriber(key, spawnEvents, callback), - } -} diff --git a/packages/fcl-core/src/events/legacy-events.ts b/packages/fcl-core/src/events/legacy-events.ts new file mode 100644 index 000000000..e13566811 --- /dev/null +++ b/packages/fcl-core/src/events/legacy-events.ts @@ -0,0 +1,97 @@ +import { + block, + config, + decode, + getEventsAtBlockHeightRange, + send, +} from "@onflow/sdk" +import type {Block, Event} from "@onflow/typedefs" +import { + ActorContext, + ActorHandlers, + Letter, + spawn, + SUBSCRIBE, + subscriber, + UNSUBSCRIBE, +} from "@onflow/util-actor" + +export interface SubscribeObject { + /** + * @description Subscribe to events + * @param callback The callback function + * @returns A function to unsubscribe + */ + subscribe: ( + callback: (data: Event | null, error: Error | null) => void + ) => () => void +} + +const RATE: number = 10000 +const UPDATED: string = "UPDATED" +const TICK: string = "TICK" +const HIGH_WATER_MARK: string = "hwm" + +const scheduleTick = async (ctx: ActorContext): Promise => { + return setTimeout( + () => ctx.sendSelf(TICK), + await config().get("fcl.eventPollRate", RATE) + ) +} + +const HANDLERS: ActorHandlers = { + [TICK]: async (ctx: ActorContext): Promise => { + if (!ctx.hasSubs()) return + let hwm: Block | null = ctx.get(HIGH_WATER_MARK) + if (hwm == null) { + ctx.put(HIGH_WATER_MARK, await block()) + ctx.put(TICK, await scheduleTick(ctx)) + } else { + let next: Block = await block() + ctx.put(HIGH_WATER_MARK, next) + if (hwm.height < next.height) { + const data: Event[] = await send([ + getEventsAtBlockHeightRange(ctx.self(), hwm.height + 1, next.height), + ]).then(decode) + for (let d of data) ctx.broadcast(UPDATED, d) + } + ctx.put(TICK, await scheduleTick(ctx)) + } + }, + [SUBSCRIBE]: async (ctx: ActorContext, letter: Letter): Promise => { + if (!ctx.hasSubs()) { + ctx.put(TICK, await scheduleTick(ctx)) + } + ctx.subscribe(letter.from) + }, + [UNSUBSCRIBE]: (ctx: ActorContext, letter: Letter): void => { + ctx.unsubscribe(letter.from) + if (!ctx.hasSubs()) { + clearTimeout(ctx.get(TICK)) + ctx.delete(TICK) + ctx.delete(HIGH_WATER_MARK) + } + }, +} + +const spawnEvents = (key?: string): string => spawn(HANDLERS, key) + +/** + * @description Subscribe to events + * @param key A valid event name + * @returns An object with a subscribe method + * + * @example + * import * as fcl from "@onflow/fcl" + * fcl.events(eventName).subscribe((event) => console.log(event)) + */ +export function events(key: string): SubscribeObject { + return { + /** + * @description Subscribe to events + * @param {Function} callback The callback function + * @returns {SubscriptionCallback} + */ + subscribe: callback => subscriber(key, spawnEvents, callback), + } +} From 1341b5c49753c923873bc76581ca7f2196243d4d Mon Sep 17 00:00:00 2001 From: mfbz Date: Mon, 26 May 2025 11:24:24 +0200 Subject: [PATCH 2/2] Fixed for compatibility --- packages/fcl-core/src/events/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/fcl-core/src/events/index.ts b/packages/fcl-core/src/events/index.ts index cfd9ad603..58abe3f30 100644 --- a/packages/fcl-core/src/events/index.ts +++ b/packages/fcl-core/src/events/index.ts @@ -65,11 +65,13 @@ export function events(filterOrType?: EventFilter | string) { ) } unsubscribeFnLegacy = legacyEvents(filterOrType).subscribe( - (event: Event, error?: Error) => { + (event: Event | null, error: Error | null) => { if (error) { onError(error) } else { - onData(event) + if (event) { + onData(event) + } } } )