@open-mercato/ui 0.9.0 → 0.9.1-develop.7459.1.99e3accd30

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.
@@ -7,6 +7,7 @@ import type { ProgressJobDto, UseProgressPollResult } from './useProgressPoll'
7
7
  import { applyLocalProgressUpdate, isLocalProgressJob } from './useProgressPoll'
8
8
 
9
9
  const SSE_PROGRESS_SYNC_INTERVAL = 5000
10
+ const SSE_PROGRESS_IDLE_RECONCILE_INTERVAL = 30000
10
11
 
11
12
  function isVisibleProgressJob(job: ProgressJobDto): boolean {
12
13
  return job.meta?.hiddenFromTopBar !== true
@@ -69,10 +70,26 @@ export function useProgressSse(): UseProgressPollResult {
69
70
  void fetchJobs()
70
71
  }, [fetchJobs])
71
72
 
73
+ // The cross-process bridge (packages/events/src/bridge.ts) delivers
74
+ // broadcast events over Postgres LISTEN/NOTIFY, which has no replay: a
75
+ // notify published during a listener reconnect window is lost for good.
76
+ // Poll fast while a job is active, and fall back to a slow reconciliation
77
+ // poll while idle so a missed `progress.job.created` still surfaces.
78
+ // See `.ai/lessons/worker-emitted-progress-needs-polling-fallback-even.md`.
79
+ const hasActiveJobs = activeJobs.length > 0
80
+
72
81
  React.useEffect(() => {
73
- let interval: ReturnType<typeof setInterval> | null = setInterval(() => {
74
- void fetchJobs()
75
- }, SSE_PROGRESS_SYNC_INTERVAL)
82
+ let interval: ReturnType<typeof setInterval> | null = null
83
+
84
+ const startInterval = () => {
85
+ if (interval) clearInterval(interval)
86
+ if (document.hidden) return
87
+ interval = setInterval(() => {
88
+ void fetchJobs()
89
+ }, hasActiveJobs ? SSE_PROGRESS_SYNC_INTERVAL : SSE_PROGRESS_IDLE_RECONCILE_INTERVAL)
90
+ }
91
+
92
+ startInterval()
76
93
 
77
94
  const onVisibilityChange = () => {
78
95
  if (document.hidden) {
@@ -82,10 +99,7 @@ export function useProgressSse(): UseProgressPollResult {
82
99
  }
83
100
  } else {
84
101
  void fetchJobs()
85
- if (interval) clearInterval(interval)
86
- interval = setInterval(() => {
87
- void fetchJobs()
88
- }, SSE_PROGRESS_SYNC_INTERVAL)
102
+ startInterval()
89
103
  }
90
104
  }
91
105
 
@@ -94,7 +108,7 @@ export function useProgressSse(): UseProgressPollResult {
94
108
  if (interval) clearInterval(interval)
95
109
  document.removeEventListener('visibilitychange', onVisibilityChange)
96
110
  }
97
- }, [fetchJobs])
111
+ }, [fetchJobs, hasActiveJobs])
98
112
 
99
113
  React.useEffect(() => {
100
114
  return subscribeProgressUpdate((detail) => {