feat(connect): connector status + Synka nu row in Settings -> Abonnemang (PR6b-3) (#2104)
* feat(connect): connector status + Synka nu row in Settings -> Abonnemang (PR6b-3) Self-host only: shows per-upstream connector mode, key prefix, and the active company's granted capabilities from GET /api/connector/status, plus a manual run of the entitlement sync via the new authed POST /api/connector/sync (requireWrite, 60s cooldown) instead of waiting for the hourly cron. Hidden on hosted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KAUKbGUGtAmRhpDKfn84F5 * fix(connect): handle sync fetch rejection, count capabilities not rows, not_configured toast Skeptic findings on the Synka nu flow: a rejected fetch (instance restarting) was a silent no-op with an unhandled rejection; the success toast printed grant rows (companies x scopes) as capabilities; a not_configured outcome claimed the hosted service was unreachable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KAUKbGUGtAmRhpDKfn84F5 --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
aabddb592f
commit
ee22c9c7b7
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Cooldown for the operator-triggered connector sync (POST /api/connector/sync).
|
||||
* Every run POSTs the instance's company count to the hosted entitlements
|
||||
* endpoint, so a click storm in the settings panel must not turn into a
|
||||
* request storm against the hosted service. Module-level state is enough:
|
||||
* self-hosted runs as one long-lived process, and the hourly cron is
|
||||
* unaffected (it never goes through this gate).
|
||||
*/
|
||||
export const MANUAL_SYNC_COOLDOWN_MS = 60_000
|
||||
|
||||
let inFlight = false
|
||||
let lastStartedAt = 0
|
||||
|
||||
/** Claims the sync slot; false while a sync runs or the cooldown holds. */
|
||||
export function tryBeginManualSync(now: number = Date.now()): boolean {
|
||||
if (inFlight || now - lastStartedAt < MANUAL_SYNC_COOLDOWN_MS) return false
|
||||
inFlight = true
|
||||
lastStartedAt = now
|
||||
return true
|
||||
}
|
||||
|
||||
export function endManualSync(): void {
|
||||
inFlight = false
|
||||
}
|
||||
|
||||
/** Test hook: clears the in-flight flag and the cooldown window. */
|
||||
export function resetManualSyncThrottle(): void {
|
||||
inFlight = false
|
||||
lastStartedAt = 0
|
||||
}
|
||||
Reference in New Issue
Block a user