From 5b3ba8186c571be07f9f020ca7207c2306d4f860 Mon Sep 17 00:00:00 2001 From: pdmarf <135653545+pdmarf@users.noreply.github.com> Date: Wed, 2 Sep 2026 11:16:24 +0100 Subject: [PATCH] v1.0.46: clear stale running-timer state even when stopTimer fails in Notion The onKeyDown stop/switch paths only cleared memRunningActionId/EntryId after a successful stopTimer call. If the tracked Notion entry was already gone (archived/deleted/edited outside the plugin), stopTimer threw and the stale ID was never cleared -- every subsequent keypress retried the same doomed stop call, showed a warning triangle, and the deck got permanently stuck (unable to unselect the stuck button or start any new timer). checkElapsed already handled this correctly by clearing state unconditionally; onKeyDown now does the same: stopTimer failures are logged but non-fatal, and local state clears regardless. --- com.pdma.notion-timer.sdPlugin/bin/plugin.js | 14 +++++++++++--- .../bin/plugin.js.sig | 2 +- notion-timer.streamDeckPlugin | Bin 99649 -> 99749 bytes src/plugin.ts | 18 +++++++++++++++--- version.json | 2 +- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/com.pdma.notion-timer.sdPlugin/bin/plugin.js b/com.pdma.notion-timer.sdPlugin/bin/plugin.js index 7662065..7ed249e 100644 --- a/com.pdma.notion-timer.sdPlugin/bin/plugin.js +++ b/com.pdma.notion-timer.sdPlugin/bin/plugin.js @@ -6438,7 +6438,7 @@ async function stopTimer(token, entryId) { } // src/plugin.ts -var CURRENT_VERSION = "1.0.45"; +var CURRENT_VERSION = "1.0.46"; var GITEA_BASE = "https://gitea.pdmarf.co.uk/pdm/stream_deck_notion_timer/raw/branch/stable-rebuild"; var SIGNING_PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAN7ko8TUpuPzPAJuKAZCRjV0c4ZSlou5d9pUAF6o12b4= @@ -6677,13 +6677,21 @@ var TimerToggle = class extends SingletonAction { } try { if (isRunning) { - await stopTimer(global.notionToken, memRunningEntryId); + try { + await stopTimer(global.notionToken, memRunningEntryId); + } catch (err) { + plugin_default.logger.error("Failed to stop timer in Notion (clearing local state anyway):", err); + } setRunningEntry(null, null); this.clearElapsedCheck(); await Promise.all([ev.action.setState(0), ev.action.setTitle(title)]); } else { if (memRunningEntryId) { - await stopTimer(global.notionToken, memRunningEntryId); + try { + await stopTimer(global.notionToken, memRunningEntryId); + } catch (err) { + plugin_default.logger.error("Failed to stop previous timer in Notion (clearing local state anyway):", err); + } setRunningEntry(null, null); this.clearElapsedCheck(); } diff --git a/com.pdma.notion-timer.sdPlugin/bin/plugin.js.sig b/com.pdma.notion-timer.sdPlugin/bin/plugin.js.sig index 1f31d42..0b3f985 100644 --- a/com.pdma.notion-timer.sdPlugin/bin/plugin.js.sig +++ b/com.pdma.notion-timer.sdPlugin/bin/plugin.js.sig @@ -1 +1 @@ -696’``w¾)G¶"éoÛ£šAyÍ‹xìØ“ÁÞ ¶á„ÙdG»Cv+t9ãXÅ­ü]M>IÁ¨Í–¼š²ßÁ \ No newline at end of file +%ÔC¹K$ñh­¸O×Ù~…‘cc¨'cwMá�¸þÀ›¸\ÞÝAä¨�ty"0|ÉiîbRö»/Îå„/¡ \ No newline at end of file diff --git a/notion-timer.streamDeckPlugin b/notion-timer.streamDeckPlugin index 853aae66f88e985a5313c2684f2c65812120afbb..58010aaec33f09d04e1a5d0a7e4142936f67a972 100644 GIT binary patch delta 1462 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 diff --git a/src/plugin.ts b/src/plugin.ts index 3882eb5..6d18d42 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -1,4 +1,4 @@ -const CURRENT_VERSION = "1.0.45"; +const CURRENT_VERSION = "1.0.46"; const GITEA_BASE = "https://gitea.pdmarf.co.uk/pdm/stream_deck_notion_timer/raw/branch/stable-rebuild"; const SIGNING_PUBLIC_KEY = `-----BEGIN PUBLIC KEY----- MCowBQYDK2VwAyEAN7ko8TUpuPzPAJuKAZCRjV0c4ZSlou5d9pUAF6o12b4= @@ -286,13 +286,25 @@ class TimerToggle extends SingletonAction { try { if (isRunning) { - await stopTimer(global.notionToken, memRunningEntryId!); + // Stopping the entry in Notion is best-effort: if the page is already + // gone/archived (e.g. edited outside the plugin) this throws, but the + // local "running" tracking must clear anyway or every future keypress + // retries this same doomed stop call and the deck gets stuck forever. + try { + await stopTimer(global.notionToken, memRunningEntryId!); + } catch (err) { + streamDeck.logger.error("Failed to stop timer in Notion (clearing local state anyway):", err); + } setRunningEntry(null, null); this.clearElapsedCheck(); await Promise.all([ev.action.setState(0), ev.action.setTitle(title)]); } else { if (memRunningEntryId) { - await stopTimer(global.notionToken, memRunningEntryId); + try { + await stopTimer(global.notionToken, memRunningEntryId); + } catch (err) { + streamDeck.logger.error("Failed to stop previous timer in Notion (clearing local state anyway):", err); + } setRunningEntry(null, null); this.clearElapsedCheck(); } diff --git a/version.json b/version.json index 1cbc25d..03c4c7f 100644 --- a/version.json +++ b/version.json @@ -1 +1 @@ -{ "version": "1.0.45" } +{ "version": "1.0.46" }