-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathsession-view.ts
More file actions
92 lines (85 loc) · 3.07 KB
/
Copy pathsession-view.ts
File metadata and controls
92 lines (85 loc) · 3.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import type { InternalSessionRow, SessionStateResponse } from './types'
function limitedModeReasonFromRow(row: InternalSessionRow) {
if ((row.access_tier ?? 'full') !== 'limited') return {}
return {
countryCode: row.country_code ?? null,
countryBlockReason: row.country_block_reason ?? null,
ipPrivacySignals: row.ip_privacy_signals ?? null,
}
}
/**
* Pure function converting an internal session row (or absence thereof) into
* the public response shape. Never reads the clock — caller supplies `now` so
* behavior is deterministic under test.
*
* Returns null only when the row is past the grace window — the caller
* should treat that as "no session" and either re-queue or surface
* `{ status: 'none' }` to the client.
*/
export function toSessionStateResponse(params: {
row: InternalSessionRow | null
position: number
/** Snapshot of every model's queue depth at response time. Only consumed
* by the `queued` variant — active/ended don't need the selector. */
queueDepthByModel: Record<string, number>
graceMs: number
now: Date
}): SessionStateResponse | null {
const { row, position, queueDepthByModel, graceMs, now } = params
if (!row) return null
if (row.status === 'active' && row.expires_at) {
const expiresAtMs = row.expires_at.getTime()
const nowMs = now.getTime()
if (expiresAtMs > nowMs) {
return {
status: 'active',
accessTier: row.access_tier ?? 'full',
instanceId: row.active_instance_id,
model: row.model,
admittedAt: (row.admitted_at ?? row.created_at).toISOString(),
expiresAt: row.expires_at.toISOString(),
remainingMs: expiresAtMs - nowMs,
...limitedModeReasonFromRow(row),
}
}
const graceEndsMs = expiresAtMs + graceMs
if (graceEndsMs > nowMs) {
return {
status: 'ended',
accessTier: row.access_tier ?? 'full',
instanceId: row.active_instance_id,
admittedAt: (row.admitted_at ?? row.created_at).toISOString(),
expiresAt: row.expires_at.toISOString(),
gracePeriodEndsAt: new Date(graceEndsMs).toISOString(),
gracePeriodRemainingMs: graceEndsMs - nowMs,
...limitedModeReasonFromRow(row),
}
}
}
if (row.status === 'queued') {
return {
status: 'queued',
accessTier: row.access_tier ?? 'full',
instanceId: row.active_instance_id,
model: row.model,
position,
queueDepth: queueDepthByModel[row.model] ?? 0,
queueDepthByModel,
estimatedWaitMs: estimateWaitMs({ position }),
queuedAt: row.queued_at.toISOString(),
...limitedModeReasonFromRow(row),
}
}
// active row past the grace window — callers should treat as "no session" and re-queue
return null
}
const WAIT_MS_PER_SPOT_AHEAD = 24_000
/**
* Rough wait-time estimate shown to queued users: 24 seconds per spot ahead.
* Position 1 → 0ms (next tick picks you up).
*/
export function estimateWaitMs(params: { position: number }): number {
const { position } = params
if (position <= 1) return 0
return (position - 1) * WAIT_MS_PER_SPOT_AHEAD
}