ee22c9c7b7
* 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>
31 lines
1.0 KiB
TypeScript
31 lines
1.0 KiB
TypeScript
/**
|
|
* 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
|
|
}
|