@rawdash/sdk-runtime 0.27.0 → 0.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ interface SubscribeCallbacks {
5
5
  onWidgetUnchanged?: (widget: CachedWidget) => void;
6
6
  onWidgetFailing?: (widget: CachedWidget) => void;
7
7
  onError?: (error: unknown) => void;
8
+ onBootstrapped?: () => void;
8
9
  }
9
10
  interface SubscribeOptions {
10
11
  syncingPollMs?: number;
@@ -13,6 +14,9 @@ interface SubscribeOptions {
13
14
  failingBackoffMs?: number;
14
15
  lateRetryStartMs?: number;
15
16
  lateRetryMaxMs?: number;
17
+ bootstrapRetryStartMs?: number;
18
+ bootstrapRetryMaxMs?: number;
19
+ bootstrapErrorAfterAttempts?: number;
16
20
  defaultIntervalSeconds?: number;
17
21
  jitterMs?: number;
18
22
  now?: () => number;
@@ -32,6 +36,9 @@ interface ResolvedOptions {
32
36
  failingBackoffMs: number;
33
37
  lateRetryStartMs: number;
34
38
  lateRetryMaxMs: number;
39
+ bootstrapRetryStartMs: number;
40
+ bootstrapRetryMaxMs: number;
41
+ bootstrapErrorAfterAttempts: number;
35
42
  defaultIntervalSeconds: number;
36
43
  jitterMs: number;
37
44
  }
package/dist/index.js CHANGED
@@ -6,6 +6,9 @@ var DEFAULT_OPTIONS = {
6
6
  failingBackoffMs: 6e4,
7
7
  lateRetryStartMs: 3e3,
8
8
  lateRetryMaxMs: 3e4,
9
+ bootstrapRetryStartMs: 1e3,
10
+ bootstrapRetryMaxMs: 3e4,
11
+ bootstrapErrorAfterAttempts: 3,
9
12
  defaultIntervalSeconds: 300,
10
13
  jitterMs: 2e3
11
14
  };
@@ -23,6 +26,17 @@ function subscribe(source, dashboardId, callbacks, options = {}) {
23
26
  let stopped = false;
24
27
  let visibilityCleanup = null;
25
28
  let bootstrapRetryHandle = null;
29
+ let bootstrapSettled = false;
30
+ let bootstrapAttempts = 0;
31
+ let bootstrapRetryDelayMs = 0;
32
+ let bootstrapRetryPending = false;
33
+ function settleBootstrap() {
34
+ if (bootstrapSettled) {
35
+ return;
36
+ }
37
+ bootstrapSettled = true;
38
+ callbacks.onBootstrapped?.();
39
+ }
26
40
  function schedule(t, delayMs) {
27
41
  if (stopped) {
28
42
  return;
@@ -89,24 +103,44 @@ function subscribe(source, dashboardId, callbacks, options = {}) {
89
103
  if (stopped) {
90
104
  return;
91
105
  }
106
+ bootstrapAttempts = 0;
107
+ bootstrapRetryDelayMs = 0;
92
108
  for (const widget of widgets) {
93
109
  applyWidget(widget);
94
110
  }
111
+ settleBootstrap();
95
112
  } catch (err) {
96
113
  if (stopped) {
97
114
  return;
98
115
  }
99
- callbacks.onError?.(err);
100
- if (bootstrapRetryHandle !== null) {
101
- clearTimer(bootstrapRetryHandle);
116
+ bootstrapAttempts += 1;
117
+ if (bootstrapAttempts >= opts.bootstrapErrorAfterAttempts) {
118
+ settleBootstrap();
119
+ callbacks.onError?.(err);
102
120
  }
103
- bootstrapRetryHandle = setTimer(() => {
104
- bootstrapRetryHandle = null;
105
- if (!stopped) {
106
- void bootstrap();
107
- }
108
- }, opts.failingBackoffMs);
121
+ bootstrapRetryDelayMs = bootstrapRetryDelayMs <= 0 ? Math.max(1, opts.bootstrapRetryStartMs) : Math.min(bootstrapRetryDelayMs * 2, opts.bootstrapRetryMaxMs);
122
+ scheduleBootstrapRetry();
123
+ }
124
+ }
125
+ function scheduleBootstrapRetry() {
126
+ if (stopped) {
127
+ return;
128
+ }
129
+ if (bootstrapRetryHandle !== null) {
130
+ clearTimer(bootstrapRetryHandle);
131
+ bootstrapRetryHandle = null;
132
+ }
133
+ if (visibility && visibility.isHidden()) {
134
+ bootstrapRetryPending = true;
135
+ return;
109
136
  }
137
+ bootstrapRetryPending = false;
138
+ bootstrapRetryHandle = setTimer(() => {
139
+ bootstrapRetryHandle = null;
140
+ if (!stopped) {
141
+ void bootstrap();
142
+ }
143
+ }, bootstrapRetryDelayMs);
110
144
  }
111
145
  if (visibility) {
112
146
  visibilityCleanup = visibility.onChange(() => {
@@ -120,10 +154,18 @@ function subscribe(source, dashboardId, callbacks, options = {}) {
120
154
  t.timer = null;
121
155
  }
122
156
  }
157
+ if (bootstrapRetryHandle !== null) {
158
+ clearTimer(bootstrapRetryHandle);
159
+ bootstrapRetryHandle = null;
160
+ bootstrapRetryPending = true;
161
+ }
123
162
  } else {
124
163
  for (const t of trackers.values()) {
125
164
  schedule(t, 0);
126
165
  }
166
+ if (bootstrapRetryPending) {
167
+ scheduleBootstrapRetry();
168
+ }
127
169
  }
128
170
  });
129
171
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/engine.ts"],"sourcesContent":["import type { CachedWidget, DataSource, WidgetSyncState } from '@rawdash/core';\n\nexport interface SubscribeCallbacks {\n onWidgetUpdated: (widget: CachedWidget) => void;\n onWidgetUnchanged?: (widget: CachedWidget) => void;\n onWidgetFailing?: (widget: CachedWidget) => void;\n onError?: (error: unknown) => void;\n}\n\nexport interface SubscribeOptions {\n syncingPollMs?: number;\n syncingPollMaxMs?: number;\n unsyncedPollMs?: number;\n failingBackoffMs?: number;\n lateRetryStartMs?: number;\n lateRetryMaxMs?: number;\n defaultIntervalSeconds?: number;\n jitterMs?: number;\n now?: () => number;\n setTimeout?: (cb: () => void, ms: number) => unknown;\n clearTimeout?: (handle: unknown) => void;\n random?: () => number;\n visibility?: VisibilitySource | null;\n}\n\nexport interface VisibilitySource {\n isHidden(): boolean;\n onChange(listener: () => void): () => void;\n}\n\ninterface ResolvedOptions {\n syncingPollMs: number;\n syncingPollMaxMs: number;\n unsyncedPollMs: number;\n failingBackoffMs: number;\n lateRetryStartMs: number;\n lateRetryMaxMs: number;\n defaultIntervalSeconds: number;\n jitterMs: number;\n}\n\nconst DEFAULT_OPTIONS: ResolvedOptions = {\n syncingPollMs: 3_000,\n syncingPollMaxMs: 60_000,\n unsyncedPollMs: 10_000,\n failingBackoffMs: 60_000,\n lateRetryStartMs: 3_000,\n lateRetryMaxMs: 30_000,\n defaultIntervalSeconds: 300,\n jitterMs: 2_000,\n};\n\ntype Timer = unknown;\n\ninterface WidgetTracker {\n widgetId: string;\n lastSyncAtMs: number | null;\n lastSyncState: WidgetSyncState | undefined;\n failingNotified: boolean;\n lateRetryDelayMs: number | null;\n syncingSinceMs: number | null;\n timer: Timer | null;\n}\n\nexport type Unsubscribe = () => void;\n\nexport function subscribe(\n source: DataSource,\n dashboardId: string,\n callbacks: SubscribeCallbacks,\n options: SubscribeOptions = {},\n): Unsubscribe {\n const opts = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n const now = opts.now ?? (() => Date.now());\n const setTimer = opts.setTimeout ?? ((cb, ms) => setTimeout(cb, ms));\n const clearTimer = opts.clearTimeout ?? ((h) => clearTimeout(h as never));\n const random = opts.random ?? Math.random;\n const visibility = opts.visibility ?? defaultVisibility();\n\n const trackers = new Map<string, WidgetTracker>();\n let stopped = false;\n let visibilityCleanup: (() => void) | null = null;\n let bootstrapRetryHandle: Timer | null = null;\n\n function schedule(t: WidgetTracker, delayMs: number): void {\n if (stopped) {\n return;\n }\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n if (visibility && visibility.isHidden()) {\n return;\n }\n const jitter = Math.floor(random() * opts.jitterMs);\n t.timer = setTimer(\n () => {\n t.timer = null;\n void poll(t);\n },\n Math.max(0, delayMs + jitter),\n );\n }\n\n function tracker(widgetId: string): WidgetTracker {\n let t = trackers.get(widgetId);\n if (!t) {\n t = {\n widgetId,\n lastSyncAtMs: null,\n lastSyncState: undefined,\n failingNotified: false,\n lateRetryDelayMs: null,\n syncingSinceMs: null,\n timer: null,\n };\n trackers.set(widgetId, t);\n }\n return t;\n }\n\n function applyWidget(widget: CachedWidget): void {\n const t = tracker(widget.widgetId);\n const nextDelay = handleWidget(t, widget, now(), opts, callbacks);\n schedule(t, nextDelay);\n }\n\n async function poll(t: WidgetTracker): Promise<void> {\n if (stopped) {\n return;\n }\n try {\n const widget = await source.getWidget(dashboardId, t.widgetId);\n if (stopped) {\n return;\n }\n const nextDelay = handleWidget(t, widget, now(), opts, callbacks);\n schedule(t, nextDelay);\n } catch (err) {\n if (stopped) {\n return;\n }\n callbacks.onError?.(err);\n schedule(t, opts.failingBackoffMs);\n }\n }\n\n async function bootstrap(): Promise<void> {\n try {\n const widgets = await source.getWidgets(dashboardId);\n if (stopped) {\n return;\n }\n for (const widget of widgets) {\n applyWidget(widget);\n }\n } catch (err) {\n if (stopped) {\n return;\n }\n callbacks.onError?.(err);\n if (bootstrapRetryHandle !== null) {\n clearTimer(bootstrapRetryHandle);\n }\n bootstrapRetryHandle = setTimer(() => {\n bootstrapRetryHandle = null;\n if (!stopped) {\n void bootstrap();\n }\n }, opts.failingBackoffMs);\n }\n }\n\n if (visibility) {\n visibilityCleanup = visibility.onChange(() => {\n if (stopped) {\n return;\n }\n if (visibility.isHidden()) {\n for (const t of trackers.values()) {\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n }\n } else {\n for (const t of trackers.values()) {\n schedule(t, 0);\n }\n }\n });\n }\n\n void bootstrap();\n\n return () => {\n stopped = true;\n for (const t of trackers.values()) {\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n }\n if (bootstrapRetryHandle !== null) {\n clearTimer(bootstrapRetryHandle);\n bootstrapRetryHandle = null;\n }\n if (visibilityCleanup) {\n visibilityCleanup();\n }\n };\n}\n\nexport function handleWidget(\n t: WidgetTracker,\n widget: CachedWidget,\n nowMs: number,\n opts: ResolvedOptions,\n callbacks: SubscribeCallbacks,\n): number {\n const incomingSyncAtMs = widget.cachedAt\n ? new Date(widget.cachedAt).getTime()\n : null;\n const rawIntervalSeconds =\n widget.syncIntervalSeconds ?? opts.defaultIntervalSeconds;\n const safeIntervalSeconds =\n Number.isFinite(rawIntervalSeconds) && rawIntervalSeconds > 0\n ? rawIntervalSeconds\n : opts.defaultIntervalSeconds;\n const intervalMs = safeIntervalSeconds * 1000;\n const state = widget.syncState;\n\n const previousSyncAtMs = t.lastSyncAtMs;\n const advanced =\n incomingSyncAtMs !== null && incomingSyncAtMs !== previousSyncAtMs;\n\n switch (state) {\n case 'fresh': {\n if (advanced || previousSyncAtMs === null) {\n t.lastSyncAtMs = incomingSyncAtMs;\n t.lastSyncState = state;\n t.failingNotified = false;\n t.lateRetryDelayMs = null;\n t.syncingSinceMs = null;\n callbacks.onWidgetUpdated(widget);\n if (incomingSyncAtMs === null) {\n return intervalMs;\n }\n const expected = incomingSyncAtMs + intervalMs;\n return Math.max(0, expected - nowMs);\n }\n callbacks.onWidgetUnchanged?.(widget);\n const expected = (incomingSyncAtMs ?? nowMs) + intervalMs;\n const baseDelay = Math.max(0, expected - nowMs);\n const giveUpAtMs = (incomingSyncAtMs ?? nowMs) + 2 * intervalMs;\n if (nowMs >= giveUpAtMs) {\n t.lateRetryDelayMs = null;\n return Math.max(baseDelay, intervalMs);\n }\n const prev = t.lateRetryDelayMs ?? 0;\n const next =\n prev === 0\n ? opts.lateRetryStartMs\n : Math.min(prev * 2, opts.lateRetryMaxMs);\n t.lateRetryDelayMs = next;\n t.lastSyncState = state;\n return next;\n }\n case 'syncing': {\n t.lastSyncState = state;\n if (t.syncingSinceMs === null) {\n t.syncingSinceMs = nowMs;\n }\n callbacks.onWidgetUnchanged?.(widget);\n const elapsed = nowMs - t.syncingSinceMs;\n if (elapsed >= opts.syncingPollMaxMs) {\n return intervalMs;\n }\n return opts.syncingPollMs;\n }\n case 'failing':\n case 'stale': {\n t.lastSyncState = state;\n if (!t.failingNotified) {\n t.failingNotified = true;\n callbacks.onWidgetFailing?.(widget);\n } else {\n callbacks.onWidgetUnchanged?.(widget);\n }\n return opts.failingBackoffMs;\n }\n case 'unsynced': {\n t.lastSyncState = state;\n callbacks.onWidgetUnchanged?.(widget);\n return opts.unsyncedPollMs;\n }\n default: {\n if (advanced || previousSyncAtMs === null) {\n t.lastSyncAtMs = incomingSyncAtMs;\n callbacks.onWidgetUpdated(widget);\n } else {\n callbacks.onWidgetUnchanged?.(widget);\n }\n t.lastSyncState = state;\n return intervalMs;\n }\n }\n}\n\nfunction defaultVisibility(): VisibilitySource | null {\n if (typeof document === 'undefined') {\n return null;\n }\n const doc = document;\n return {\n isHidden: () => doc.hidden === true,\n onChange: (listener) => {\n const handler = () => listener();\n doc.addEventListener('visibilitychange', handler);\n if (typeof window !== 'undefined') {\n window.addEventListener('focus', handler);\n }\n return () => {\n doc.removeEventListener('visibilitychange', handler);\n if (typeof window !== 'undefined') {\n window.removeEventListener('focus', handler);\n }\n };\n },\n };\n}\n"],"mappings":"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","names":["expected"]}
1
+ {"version":3,"sources":["../src/engine.ts"],"sourcesContent":["import type { CachedWidget, DataSource, WidgetSyncState } from '@rawdash/core';\n\nexport interface SubscribeCallbacks {\n onWidgetUpdated: (widget: CachedWidget) => void;\n onWidgetUnchanged?: (widget: CachedWidget) => void;\n onWidgetFailing?: (widget: CachedWidget) => void;\n onError?: (error: unknown) => void;\n onBootstrapped?: () => void;\n}\n\nexport interface SubscribeOptions {\n syncingPollMs?: number;\n syncingPollMaxMs?: number;\n unsyncedPollMs?: number;\n failingBackoffMs?: number;\n lateRetryStartMs?: number;\n lateRetryMaxMs?: number;\n bootstrapRetryStartMs?: number;\n bootstrapRetryMaxMs?: number;\n bootstrapErrorAfterAttempts?: number;\n defaultIntervalSeconds?: number;\n jitterMs?: number;\n now?: () => number;\n setTimeout?: (cb: () => void, ms: number) => unknown;\n clearTimeout?: (handle: unknown) => void;\n random?: () => number;\n visibility?: VisibilitySource | null;\n}\n\nexport interface VisibilitySource {\n isHidden(): boolean;\n onChange(listener: () => void): () => void;\n}\n\ninterface ResolvedOptions {\n syncingPollMs: number;\n syncingPollMaxMs: number;\n unsyncedPollMs: number;\n failingBackoffMs: number;\n lateRetryStartMs: number;\n lateRetryMaxMs: number;\n bootstrapRetryStartMs: number;\n bootstrapRetryMaxMs: number;\n bootstrapErrorAfterAttempts: number;\n defaultIntervalSeconds: number;\n jitterMs: number;\n}\n\nconst DEFAULT_OPTIONS: ResolvedOptions = {\n syncingPollMs: 3_000,\n syncingPollMaxMs: 60_000,\n unsyncedPollMs: 10_000,\n failingBackoffMs: 60_000,\n lateRetryStartMs: 3_000,\n lateRetryMaxMs: 30_000,\n bootstrapRetryStartMs: 1_000,\n bootstrapRetryMaxMs: 30_000,\n bootstrapErrorAfterAttempts: 3,\n defaultIntervalSeconds: 300,\n jitterMs: 2_000,\n};\n\ntype Timer = unknown;\n\ninterface WidgetTracker {\n widgetId: string;\n lastSyncAtMs: number | null;\n lastSyncState: WidgetSyncState | undefined;\n failingNotified: boolean;\n lateRetryDelayMs: number | null;\n syncingSinceMs: number | null;\n timer: Timer | null;\n}\n\nexport type Unsubscribe = () => void;\n\nexport function subscribe(\n source: DataSource,\n dashboardId: string,\n callbacks: SubscribeCallbacks,\n options: SubscribeOptions = {},\n): Unsubscribe {\n const opts = {\n ...DEFAULT_OPTIONS,\n ...options,\n };\n const now = opts.now ?? (() => Date.now());\n const setTimer = opts.setTimeout ?? ((cb, ms) => setTimeout(cb, ms));\n const clearTimer = opts.clearTimeout ?? ((h) => clearTimeout(h as never));\n const random = opts.random ?? Math.random;\n const visibility = opts.visibility ?? defaultVisibility();\n\n const trackers = new Map<string, WidgetTracker>();\n let stopped = false;\n let visibilityCleanup: (() => void) | null = null;\n let bootstrapRetryHandle: Timer | null = null;\n let bootstrapSettled = false;\n let bootstrapAttempts = 0;\n let bootstrapRetryDelayMs = 0;\n let bootstrapRetryPending = false;\n\n function settleBootstrap(): void {\n if (bootstrapSettled) {\n return;\n }\n bootstrapSettled = true;\n callbacks.onBootstrapped?.();\n }\n\n function schedule(t: WidgetTracker, delayMs: number): void {\n if (stopped) {\n return;\n }\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n if (visibility && visibility.isHidden()) {\n return;\n }\n const jitter = Math.floor(random() * opts.jitterMs);\n t.timer = setTimer(\n () => {\n t.timer = null;\n void poll(t);\n },\n Math.max(0, delayMs + jitter),\n );\n }\n\n function tracker(widgetId: string): WidgetTracker {\n let t = trackers.get(widgetId);\n if (!t) {\n t = {\n widgetId,\n lastSyncAtMs: null,\n lastSyncState: undefined,\n failingNotified: false,\n lateRetryDelayMs: null,\n syncingSinceMs: null,\n timer: null,\n };\n trackers.set(widgetId, t);\n }\n return t;\n }\n\n function applyWidget(widget: CachedWidget): void {\n const t = tracker(widget.widgetId);\n const nextDelay = handleWidget(t, widget, now(), opts, callbacks);\n schedule(t, nextDelay);\n }\n\n async function poll(t: WidgetTracker): Promise<void> {\n if (stopped) {\n return;\n }\n try {\n const widget = await source.getWidget(dashboardId, t.widgetId);\n if (stopped) {\n return;\n }\n const nextDelay = handleWidget(t, widget, now(), opts, callbacks);\n schedule(t, nextDelay);\n } catch (err) {\n if (stopped) {\n return;\n }\n callbacks.onError?.(err);\n schedule(t, opts.failingBackoffMs);\n }\n }\n\n async function bootstrap(): Promise<void> {\n try {\n const widgets = await source.getWidgets(dashboardId);\n if (stopped) {\n return;\n }\n bootstrapAttempts = 0;\n bootstrapRetryDelayMs = 0;\n for (const widget of widgets) {\n applyWidget(widget);\n }\n settleBootstrap();\n } catch (err) {\n if (stopped) {\n return;\n }\n bootstrapAttempts += 1;\n if (bootstrapAttempts >= opts.bootstrapErrorAfterAttempts) {\n settleBootstrap();\n callbacks.onError?.(err);\n }\n bootstrapRetryDelayMs =\n bootstrapRetryDelayMs <= 0\n ? Math.max(1, opts.bootstrapRetryStartMs)\n : Math.min(bootstrapRetryDelayMs * 2, opts.bootstrapRetryMaxMs);\n scheduleBootstrapRetry();\n }\n }\n\n function scheduleBootstrapRetry(): void {\n if (stopped) {\n return;\n }\n if (bootstrapRetryHandle !== null) {\n clearTimer(bootstrapRetryHandle);\n bootstrapRetryHandle = null;\n }\n if (visibility && visibility.isHidden()) {\n bootstrapRetryPending = true;\n return;\n }\n bootstrapRetryPending = false;\n bootstrapRetryHandle = setTimer(() => {\n bootstrapRetryHandle = null;\n if (!stopped) {\n void bootstrap();\n }\n }, bootstrapRetryDelayMs);\n }\n\n if (visibility) {\n visibilityCleanup = visibility.onChange(() => {\n if (stopped) {\n return;\n }\n if (visibility.isHidden()) {\n for (const t of trackers.values()) {\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n }\n if (bootstrapRetryHandle !== null) {\n clearTimer(bootstrapRetryHandle);\n bootstrapRetryHandle = null;\n bootstrapRetryPending = true;\n }\n } else {\n for (const t of trackers.values()) {\n schedule(t, 0);\n }\n if (bootstrapRetryPending) {\n scheduleBootstrapRetry();\n }\n }\n });\n }\n\n void bootstrap();\n\n return () => {\n stopped = true;\n for (const t of trackers.values()) {\n if (t.timer !== null) {\n clearTimer(t.timer);\n t.timer = null;\n }\n }\n if (bootstrapRetryHandle !== null) {\n clearTimer(bootstrapRetryHandle);\n bootstrapRetryHandle = null;\n }\n if (visibilityCleanup) {\n visibilityCleanup();\n }\n };\n}\n\nexport function handleWidget(\n t: WidgetTracker,\n widget: CachedWidget,\n nowMs: number,\n opts: ResolvedOptions,\n callbacks: SubscribeCallbacks,\n): number {\n const incomingSyncAtMs = widget.cachedAt\n ? new Date(widget.cachedAt).getTime()\n : null;\n const rawIntervalSeconds =\n widget.syncIntervalSeconds ?? opts.defaultIntervalSeconds;\n const safeIntervalSeconds =\n Number.isFinite(rawIntervalSeconds) && rawIntervalSeconds > 0\n ? rawIntervalSeconds\n : opts.defaultIntervalSeconds;\n const intervalMs = safeIntervalSeconds * 1000;\n const state = widget.syncState;\n\n const previousSyncAtMs = t.lastSyncAtMs;\n const advanced =\n incomingSyncAtMs !== null && incomingSyncAtMs !== previousSyncAtMs;\n\n switch (state) {\n case 'fresh': {\n if (advanced || previousSyncAtMs === null) {\n t.lastSyncAtMs = incomingSyncAtMs;\n t.lastSyncState = state;\n t.failingNotified = false;\n t.lateRetryDelayMs = null;\n t.syncingSinceMs = null;\n callbacks.onWidgetUpdated(widget);\n if (incomingSyncAtMs === null) {\n return intervalMs;\n }\n const expected = incomingSyncAtMs + intervalMs;\n return Math.max(0, expected - nowMs);\n }\n callbacks.onWidgetUnchanged?.(widget);\n const expected = (incomingSyncAtMs ?? nowMs) + intervalMs;\n const baseDelay = Math.max(0, expected - nowMs);\n const giveUpAtMs = (incomingSyncAtMs ?? nowMs) + 2 * intervalMs;\n if (nowMs >= giveUpAtMs) {\n t.lateRetryDelayMs = null;\n return Math.max(baseDelay, intervalMs);\n }\n const prev = t.lateRetryDelayMs ?? 0;\n const next =\n prev === 0\n ? opts.lateRetryStartMs\n : Math.min(prev * 2, opts.lateRetryMaxMs);\n t.lateRetryDelayMs = next;\n t.lastSyncState = state;\n return next;\n }\n case 'syncing': {\n t.lastSyncState = state;\n if (t.syncingSinceMs === null) {\n t.syncingSinceMs = nowMs;\n }\n callbacks.onWidgetUnchanged?.(widget);\n const elapsed = nowMs - t.syncingSinceMs;\n if (elapsed >= opts.syncingPollMaxMs) {\n return intervalMs;\n }\n return opts.syncingPollMs;\n }\n case 'failing':\n case 'stale': {\n t.lastSyncState = state;\n if (!t.failingNotified) {\n t.failingNotified = true;\n callbacks.onWidgetFailing?.(widget);\n } else {\n callbacks.onWidgetUnchanged?.(widget);\n }\n return opts.failingBackoffMs;\n }\n case 'unsynced': {\n t.lastSyncState = state;\n callbacks.onWidgetUnchanged?.(widget);\n return opts.unsyncedPollMs;\n }\n default: {\n if (advanced || previousSyncAtMs === null) {\n t.lastSyncAtMs = incomingSyncAtMs;\n callbacks.onWidgetUpdated(widget);\n } else {\n callbacks.onWidgetUnchanged?.(widget);\n }\n t.lastSyncState = state;\n return intervalMs;\n }\n }\n}\n\nfunction defaultVisibility(): VisibilitySource | null {\n if (typeof document === 'undefined') {\n return null;\n }\n const doc = document;\n return {\n isHidden: () => doc.hidden === true,\n onChange: (listener) => {\n const handler = () => listener();\n doc.addEventListener('visibilitychange', handler);\n if (typeof window !== 'undefined') {\n window.addEventListener('focus', handler);\n }\n return () => {\n doc.removeEventListener('visibilitychange', handler);\n if (typeof window !== 'undefined') {\n window.removeEventListener('focus', handler);\n }\n };\n },\n };\n}\n"],"mappings":"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","names":["expected"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rawdash/sdk-runtime",
3
- "version": "0.27.0",
3
+ "version": "0.28.2",
4
4
  "description": "Rawdash auto-polling subscription engine for client-side dashboards",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -22,8 +22,8 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@rawdash/core": "0.27.0",
26
- "@rawdash/sdk-client": "0.27.0"
25
+ "@rawdash/core": "0.28.2",
26
+ "@rawdash/sdk-client": "0.28.2"
27
27
  },
28
28
  "devDependencies": {
29
29
  "tsup": "^8.0.0",