🐛 fix(client): 授权与提问提醒不再被运行状态丢掉
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
import { SETTLE_MS, THROTTLE_MS } from '../constants.js'
|
||||
import { windowIsAway } from '../platform.js'
|
||||
import { isOnScreen, stillWorth } from './session.js'
|
||||
import { isOnScreen, stillOwed } from './session.js'
|
||||
|
||||
/**
|
||||
* Build the delivery path.
|
||||
@@ -67,29 +67,33 @@ export function createDelivery({ store, copy, live, toasts, system, replay }) {
|
||||
* never actually receives.
|
||||
* @param candidate - the alert to deliver.
|
||||
* @param ignoreThrottle - deliver immediately, bypassing the flood guard.
|
||||
* @returns `false` when the flood guard suppressed this alert, `true` when the
|
||||
* delivery path itself ran (including a deliberate skip for the conversation
|
||||
* on screen).
|
||||
*/
|
||||
const deliver = (candidate, ignoreThrottle) => {
|
||||
if (ignoreThrottle !== true) {
|
||||
const now = Date.now()
|
||||
if (now - lastDelivery < THROTTLE_MS) return
|
||||
if (now - lastDelivery < THROTTLE_MS) return false
|
||||
lastDelivery = now
|
||||
}
|
||||
if (!windowIsAway()) {
|
||||
if (isOnScreen(candidate.sessionId, live.list)) return
|
||||
if (isOnScreen(candidate.sessionId, live.list)) return true
|
||||
toasts.showToast(candidate)
|
||||
recordDelivery('popup', candidate)
|
||||
return
|
||||
return true
|
||||
}
|
||||
const result = system.notifySystem(candidate, candidate.test === true)
|
||||
if (result.outcome === 'raised') {
|
||||
recordDelivery('system', candidate, result)
|
||||
if (candidate.test !== true) replay.holdForReplay(candidate, result)
|
||||
return
|
||||
return true
|
||||
}
|
||||
// A test alert still has to reach the user, and so does a real one when
|
||||
// the system channel refuses: the popup is the channel that remains.
|
||||
toasts.showToast(candidate)
|
||||
recordDelivery(`system-refused-${result.outcome}`, candidate)
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,11 +102,19 @@ export function createDelivery({ store, copy, live, toasts, system, replay }) {
|
||||
* One candidate per tick keeps the throttle meaningful, and anything still
|
||||
* queued arms its own follow-up tick — a burst used to leave every candidate
|
||||
* after the first stranded in the queue with no timer to flush it.
|
||||
*
|
||||
* A pending interaction the flood guard holds back is put back in the queue
|
||||
* instead of being dropped: only the user can clear it, so it stays owed, and
|
||||
* the next tick retries it. Flood control still drops the completions it was
|
||||
* written for.
|
||||
*/
|
||||
const flushSettle = () => {
|
||||
settleTimer = 0
|
||||
const candidate = pending.shift()
|
||||
if (candidate !== undefined && stillWorth(candidate, live)) deliver(candidate, false)
|
||||
if (candidate !== undefined && stillOwed(candidate, live)) {
|
||||
const delivered = deliver(candidate, false)
|
||||
if (delivered === false && candidate.pendingKind !== '') pending.push(candidate)
|
||||
}
|
||||
if (pending.length > 0) settleTimer = setTimeout(() => flushSettle(), SETTLE_MS)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user