(opts: {
sessionUrl: string
ingressToken: string
sessionId: string
/**
* SSE sequence-number high-water mark from the previous transport.
* Passed to the new SSETransport so its first connect() sends
* from_sequence_num / Last-Event-ID and the server resumes from where
* the old stream left off. Without this, every transport swap asks the
* server to replay the entire session history from seq 0.
*/
initialSequenceNum?: number
/**
* Worker epoch from POST /bridge response. When provided, the server
* already bumped epoch (the /bridge call IS the register — see server
* PR #293280). When omitted (v1 CCR-v2 path via replBridge.ts poll loop),
* call registerWorker as before.
*/
epoch?: number
/** CCRClient heartbeat interval. Defaults to 20s when omitted. */
heartbeatIntervalMs?: number
/** ±fraction per-beat jitter. Defaults to 0 (no jitter) when omitted. */
heartbeatJitterFraction?: number
/**
* When true, skip opening the SSE read stream — only the CCRClient write
* path is activated. Use for mirror-mode attachments that forward events
* but never receive inbound prompts or control requests.
*/
outboundOnly?: boolean
/**
* Per-instance auth header source. When provided, CCRClient + SSETransport
* read auth from this closure instead of the process-wide
* CLAUDE_CODE_SESSION_ACCESS_TOKEN env var. Required for callers managing
* multiple concurrent sessions — the env-var path stomps across sessions.
* When omitted, falls back to the env var (single-session callers).
*/
getAuthToken?: () => string | undefined
})
| 117 | * catch it and stay on the poll loop. |
| 118 | */ |
| 119 | export async function createV2ReplTransport(opts: { |
| 120 | sessionUrl: string |
| 121 | ingressToken: string |
| 122 | sessionId: string |
| 123 | /** |
| 124 | * SSE sequence-number high-water mark from the previous transport. |
| 125 | * Passed to the new SSETransport so its first connect() sends |
| 126 | * from_sequence_num / Last-Event-ID and the server resumes from where |
| 127 | * the old stream left off. Without this, every transport swap asks the |
| 128 | * server to replay the entire session history from seq 0. |
| 129 | */ |
| 130 | initialSequenceNum?: number |
| 131 | /** |
| 132 | * Worker epoch from POST /bridge response. When provided, the server |
| 133 | * already bumped epoch (the /bridge call IS the register — see server |
| 134 | * PR #293280). When omitted (v1 CCR-v2 path via replBridge.ts poll loop), |
| 135 | * call registerWorker as before. |
| 136 | */ |
| 137 | epoch?: number |
| 138 | /** CCRClient heartbeat interval. Defaults to 20s when omitted. */ |
| 139 | heartbeatIntervalMs?: number |
| 140 | /** ±fraction per-beat jitter. Defaults to 0 (no jitter) when omitted. */ |
| 141 | heartbeatJitterFraction?: number |
| 142 | /** |
| 143 | * When true, skip opening the SSE read stream — only the CCRClient write |
| 144 | * path is activated. Use for mirror-mode attachments that forward events |
| 145 | * but never receive inbound prompts or control requests. |
| 146 | */ |
| 147 | outboundOnly?: boolean |
| 148 | /** |
| 149 | * Per-instance auth header source. When provided, CCRClient + SSETransport |
| 150 | * read auth from this closure instead of the process-wide |
| 151 | * CLAUDE_CODE_SESSION_ACCESS_TOKEN env var. Required for callers managing |
| 152 | * multiple concurrent sessions — the env-var path stomps across sessions. |
| 153 | * When omitted, falls back to the env var (single-session callers). |
| 154 | */ |
| 155 | getAuthToken?: () => string | undefined |
| 156 | }): Promise<ReplBridgeTransport> { |
| 157 | const { |
| 158 | sessionUrl, |
| 159 | ingressToken, |
| 160 | sessionId, |
| 161 | initialSequenceNum, |
| 162 | getAuthToken, |
| 163 | } = opts |
| 164 | |
| 165 | // Auth header builder. If getAuthToken is provided, read from it |
| 166 | // (per-instance, multi-session safe). Otherwise write ingressToken to |
| 167 | // the process-wide env var (legacy single-session path — CCRClient's |
| 168 | // default getAuthHeaders reads it via getSessionIngressAuthHeaders). |
| 169 | let getAuthHeaders: (() => Record<string, string>) | undefined |
| 170 | if (getAuthToken) { |
| 171 | getAuthHeaders = (): Record<string, string> => { |
| 172 | const token = getAuthToken() |
| 173 | if (!token) return {} |
| 174 | return { Authorization: `Bearer ${token}` } |
| 175 | } |
| 176 | } else { |
no test coverage detected