/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
export type AuthSessionSyncEvent = {
kind: 'authenticated' | 'signed_out'
sid: string
source: string
nonce: string
timestamp: number
}
const AUTH_SYNC_CHANNEL = 'new-api:auth-session'
const AUTH_SYNC_STORAGE_KEY = 'new-api:auth-session:event'
function randomIdentifier(): string {
if (typeof globalThis.crypto?.randomUUID === 'function') {
return globalThis.crypto.randomUUID()
}
return `${Date.now()}-${Math.random().toString(36).slice(2)}`
}
const authSyncSource = randomIdentifier()
let authSyncPublisher: BroadcastChannel | null = null
function isAuthSessionSyncEvent(value: unknown): value is AuthSessionSyncEvent {
if (!value || typeof value !== 'object') return false
const event = value as Partial
return (
(event.kind === 'authenticated' || event.kind === 'signed_out') &&
typeof event.sid === 'string' &&
event.sid.length > 0 &&
typeof event.source === 'string' &&
typeof event.nonce === 'string' &&
typeof event.timestamp === 'number'
)
}
export function publishAuthSessionEvent(
kind: AuthSessionSyncEvent['kind'],
sid: string
): void {
if (typeof window === 'undefined' || !sid) return
const event: AuthSessionSyncEvent = {
kind,
sid,
source: authSyncSource,
nonce: randomIdentifier(),
timestamp: Date.now(),
}
if (typeof BroadcastChannel !== 'undefined') {
authSyncPublisher ??= new BroadcastChannel(AUTH_SYNC_CHANNEL)
authSyncPublisher.postMessage(event)
return
}
try {
window.localStorage.setItem(AUTH_SYNC_STORAGE_KEY, JSON.stringify(event))
window.localStorage.removeItem(AUTH_SYNC_STORAGE_KEY)
} catch {
// Cross-tab synchronization is best-effort when storage is unavailable.
}
}
export function subscribeAuthSessionEvents(
listener: (event: AuthSessionSyncEvent) => void
): () => void {
if (typeof window === 'undefined') return () => undefined
const deliver = (value: unknown) => {
if (
isAuthSessionSyncEvent(value) &&
value.source !== authSyncSource &&
Math.abs(Date.now() - value.timestamp) < 60_000
) {
listener(value)
}
}
if (typeof BroadcastChannel !== 'undefined') {
const channel = new BroadcastChannel(AUTH_SYNC_CHANNEL)
const handleMessage = (message: MessageEvent) => {
deliver(message.data)
}
channel.addEventListener('message', handleMessage)
return () => {
channel.removeEventListener('message', handleMessage)
channel.close()
}
}
const handleStorage = (event: StorageEvent) => {
if (event.key !== AUTH_SYNC_STORAGE_KEY || !event.newValue) return
try {
deliver(JSON.parse(event.newValue))
} catch {
// Ignore malformed same-origin storage events.
}
}
window.addEventListener('storage', handleStorage)
return () => {
window.removeEventListener('storage', handleStorage)
}
}