@cubos/agent-sdk 0.0.1140428 → 0.0.1140658

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sse.d.ts CHANGED
@@ -17,8 +17,13 @@ export interface SseOptions<T> {
17
17
  event: string | string[];
18
18
  onEvent: (data: T, event: string) => void;
19
19
  signal: AbortSignal;
20
- /** Called before each (re)connect, so the caller can mint a fresh token. */
21
- headers?: () => Promise<Record<string, string>> | Record<string, string>;
20
+ /** Called before each (re)connect, so the caller can mint a fresh token.
21
+ * `forceRefresh` is set on the one immediate retry that follows a 401 — a
22
+ * caller that caches a token must bypass the cache when it sees it, or the
23
+ * retry replays the rejected credential and the stream dies for good. */
24
+ headers?: (opts: {
25
+ forceRefresh: boolean;
26
+ }) => Promise<Record<string, string>> | Record<string, string>;
22
27
  /** Called once per successful connect, before any frame is delivered. The
23
28
  * hook a caller needs to catch up on state the stream won't replay: it fires
24
29
  * on every reconnect too, so a gap the backoff swallowed is covered as
@@ -28,8 +33,29 @@ export interface SseOptions<T> {
28
33
  * the server actually sent. */
29
34
  lastEventId?: string;
30
35
  fetchImpl?: FetchLike;
36
+ /**
37
+ * Reconnect when this many milliseconds pass with no bytes at all — not even
38
+ * a keep-alive comment. Defaults to `DEFAULT_IDLE_TIMEOUT_MS`; `0` disables.
39
+ *
40
+ * A half-open socket (a phone leaving the background, a proxy that dropped
41
+ * the connection without telling either end) leaves `read()` waiting forever,
42
+ * with nothing for the reconnect loop below to react to. The server sends a
43
+ * comment every 15s, so silence past twice that is the connection being gone
44
+ * rather than the agent being quiet.
45
+ */
46
+ idleTimeoutMs?: number;
47
+ /** Every failed attempt, transient or fatal. The loop is already reconnecting
48
+ * when this fires unless the promise also rejects. */
31
49
  onError?: (err: unknown) => void;
32
50
  }
51
+ /** Twice the server's 15s keep-alive interval: one comment may be lost to a
52
+ * hiccup without the connection being gone, two in a row means it is. */
53
+ export declare const DEFAULT_IDLE_TIMEOUT_MS = 30000;
54
+ /** Raised when the watchdog trips, so a caller logging `onError` can tell a
55
+ * connection that went silent from one that failed outright. */
56
+ export declare class SseIdleTimeout extends Error {
57
+ constructor(url: string, ms: number);
58
+ }
33
59
  /**
34
60
  * Reads `url` until `signal` aborts, reconnecting through any drop — clean
35
61
  * close from the server included, since intermediaries (Cloudflare et al.)
@@ -38,7 +64,13 @@ export interface SseOptions<T> {
38
64
  *
39
65
  * `Last-Event-ID` is replayed from the last frame the server sent, so the
40
66
  * backend's catch-up query fills whatever the gap swallowed. 4xx ends the loop
41
- * — a bad token or a deleted conversation won't fix itself by retrying.
67
+ * — a deleted conversation won't fix itself by retrying — with one exception: a
68
+ * 401 buys one immediate reconnect with `forceRefresh`, because a short-lived
69
+ * token expiring under a stream that outlives it is the expected case, not a
70
+ * misconfiguration. Only after that second rejection does the promise reject.
71
+ *
72
+ * A connection that goes silent past `idleTimeoutMs` is dropped and reopened:
73
+ * see that option for why waiting on `read()` forever is not an option.
42
74
  */
43
75
  export declare function readSse<T>(opts: SseOptions<T>): Promise<void>;
44
76
  export declare function parseFrame<T>(frame: string, expectedEvent: string | string[]): {
package/dist/sse.js CHANGED
@@ -79,6 +79,7 @@ async function raiseForStatus(res, fallback) {
79
79
 
80
80
  // src/sse.ts
81
81
  var MAX_BACKOFF_MS = 30000;
82
+ var DEFAULT_IDLE_TIMEOUT_MS = 30000;
82
83
 
83
84
  class Fatal extends Error {
84
85
  cause;
@@ -87,25 +88,54 @@ class Fatal extends Error {
87
88
  this.cause = cause;
88
89
  }
89
90
  }
91
+
92
+ class SseIdleTimeout extends Error {
93
+ constructor(url, ms) {
94
+ super(`Stream ${url} sent nothing for ${ms}ms — reconnecting.`);
95
+ this.name = "SseIdleTimeout";
96
+ }
97
+ }
90
98
  async function readSse(opts) {
91
99
  const doFetch = opts.fetchImpl ?? globalThis.fetch;
100
+ const idleMs = opts.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
92
101
  let lastEventId = opts.lastEventId;
93
102
  let attempt = 0;
103
+ let refreshing = false;
94
104
  while (!opts.signal.aborted) {
95
105
  let madeProgress = false;
106
+ const connection = new AbortController;
107
+ const unlink = forward(opts.signal, connection);
108
+ let idleTimer;
109
+ let wentIdle = false;
110
+ const armIdle = () => {
111
+ if (idleMs <= 0)
112
+ return;
113
+ clearTimeout(idleTimer);
114
+ idleTimer = setTimeout(() => {
115
+ wentIdle = true;
116
+ connection.abort();
117
+ }, idleMs);
118
+ };
96
119
  try {
97
120
  const headers = {
98
- ...await opts.headers?.(),
121
+ ...await opts.headers?.({ forceRefresh: refreshing }),
99
122
  Accept: "text/event-stream"
100
123
  };
101
124
  if (lastEventId !== undefined)
102
125
  headers["Last-Event-ID"] = lastEventId;
103
- const res = await doFetch(opts.url, { headers, signal: opts.signal });
126
+ armIdle();
127
+ const res = await doFetch(opts.url, { headers, signal: connection.signal });
104
128
  if (opts.signal.aborted)
105
129
  return;
106
- if (res.ok && res.body)
130
+ if (res.ok && res.body) {
131
+ refreshing = false;
107
132
  opts.onOpen?.();
133
+ }
108
134
  if (!res.ok || !res.body) {
135
+ if (res.status === 401 && opts.headers && !refreshing) {
136
+ refreshing = true;
137
+ continue;
138
+ }
109
139
  if (res.status >= 400 && res.status < 500) {
110
140
  await raiseForStatus(res, `Could not open ${opts.url}.`).catch((err) => {
111
141
  throw new Fatal(err);
@@ -114,7 +144,7 @@ async function readSse(opts) {
114
144
  }
115
145
  throw new Error(`stream open failed with HTTP ${res.status}`);
116
146
  }
117
- for await (const frame of frames(res.body, opts.signal)) {
147
+ for await (const frame of frames(res.body, connection.signal, armIdle)) {
118
148
  const parsed = parseFrame(frame, opts.event);
119
149
  if (parsed === null)
120
150
  continue;
@@ -123,12 +153,18 @@ async function readSse(opts) {
123
153
  opts.onEvent(parsed.data, parsed.event);
124
154
  madeProgress = true;
125
155
  }
156
+ if (wentIdle)
157
+ throw new SseIdleTimeout(opts.url, idleMs);
126
158
  } catch (err) {
127
159
  if (opts.signal.aborted)
128
160
  return;
129
161
  if (err instanceof Fatal)
130
162
  throw err.cause;
131
- opts.onError?.(err);
163
+ opts.onError?.(wentIdle ? new SseIdleTimeout(opts.url, idleMs) : err);
164
+ } finally {
165
+ clearTimeout(idleTimer);
166
+ unlink();
167
+ connection.abort();
132
168
  }
133
169
  if (opts.signal.aborted)
134
170
  return;
@@ -139,7 +175,7 @@ async function readSse(opts) {
139
175
  await sleep(delayMs, opts.signal);
140
176
  }
141
177
  }
142
- async function* frames(body, signal) {
178
+ async function* frames(body, signal, onRead) {
143
179
  const reader = body.getReader();
144
180
  const decoder = new TextDecoder;
145
181
  let buffer = "";
@@ -148,6 +184,7 @@ async function* frames(body, signal) {
148
184
  const { value, done } = await reader.read();
149
185
  if (done)
150
186
  return;
187
+ onRead();
151
188
  buffer += decoder.decode(value, { stream: true });
152
189
  for (;; ) {
153
190
  const sep = buffer.indexOf(`
@@ -200,10 +237,20 @@ function sleep(ms, signal) {
200
237
  signal.addEventListener("abort", onAbort, { once: true });
201
238
  });
202
239
  }
240
+ function forward(outer, child) {
241
+ const onAbort = () => child.abort();
242
+ if (outer.aborted)
243
+ child.abort();
244
+ else
245
+ outer.addEventListener("abort", onAbort, { once: true });
246
+ return () => outer.removeEventListener("abort", onAbort);
247
+ }
203
248
  export {
204
249
  readSse,
205
- parseFrame
250
+ parseFrame,
251
+ SseIdleTimeout,
252
+ DEFAULT_IDLE_TIMEOUT_MS
206
253
  };
207
254
 
208
- //# debugId=85857292E5DF4F6B64756E2164756E21
255
+ //# debugId=24E2FA6F4632B4F664756E2164756E21
209
256
  //# sourceMappingURL=sse.js.map
package/dist/sse.js.map CHANGED
@@ -3,9 +3,9 @@
3
3
  "sources": ["../src/errors.ts", "../src/sse.ts"],
4
4
  "sourcesContent": [
5
5
  "/** Base for everything this SDK throws, so `catch (e) { if (e instanceof\n * AgentError) }` covers both an HTTP failure and a connection that never got\n * there. */\nexport class AgentError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AgentError\";\n }\n}\n\n/** The server answered, and said no. */\nexport class AgentApiError extends AgentError {\n readonly status: number;\n /** Server's `x-request-id`, when present. Worth quoting in a bug report. */\n readonly requestId: string | null;\n /** The response body, verbatim and untruncated. Some routes explain the\n * failure in there (an MCP probe's reason, a rejected cron) in a form worth\n * showing the user; `message` only carries a truncated preview. */\n readonly body: string;\n\n constructor(message: string, status: number, requestId: string | null = null, body = \"\") {\n super(message);\n this.name = \"AgentApiError\";\n this.status = status;\n this.requestId = requestId;\n this.body = body;\n }\n\n /** The body parsed as JSON, or `undefined` when it isn't. */\n json<T = unknown>(): T | undefined {\n try {\n return JSON.parse(this.body) as T;\n } catch {\n return undefined;\n }\n }\n\n /** The token was rejected. The client already retried once with a fresh one,\n * so seeing this means `getToken` is handing back something unusable. */\n get isAuthError(): boolean {\n return this.status === 401 || this.status === 403;\n }\n\n get isNotFound(): boolean {\n return this.status === 404;\n }\n\n /** The request clashed with current state — a slug already taken, a\n * conversation that belongs to a channel, a user already blocked. */\n get isConflict(): boolean {\n return this.status === 409;\n }\n\n /** Worth retrying after a pause: the server is overloaded or briefly down. */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/**\n * The client was constructed wrong — a `baseUrl` with no scheme, most often.\n * Thrown at construction, not on the first call, so the stack points at the\n * mistake.\n */\nexport class AgentConfigError extends AgentError {\n constructor(message: string) {\n super(message);\n this.name = \"AgentConfigError\";\n }\n}\n\n/**\n * The request never produced a response: DNS, TLS, a refused connection, CORS,\n * or the timeout below.\n *\n * Without this, `fetch` rejects with a bare `TypeError: fetch failed` and the\n * caller cannot tell a wrong `baseUrl` from a server that said 500 — the two\n * need completely different fixes.\n */\nexport class AgentNetworkError extends AgentError {\n /** Whatever `fetch` (or the abort) threw. */\n readonly cause: unknown;\n /** True when the SDK's own timeout fired rather than the network failing. */\n readonly timedOut: boolean;\n\n constructor(message: string, cause: unknown, timedOut = false) {\n super(message);\n this.name = \"AgentNetworkError\";\n this.cause = cause;\n this.timedOut = timedOut;\n }\n}\n\nconst DEFAULT_MESSAGES: Record<number, string> = {\n 400: \"Invalid request.\",\n 401: \"Not authenticated.\",\n 403: \"Not allowed.\",\n 404: \"Not found.\",\n 409: \"Conflicts with the current state.\",\n 413: \"Payload too large.\",\n 429: \"Rate limited.\",\n};\n\nexport async function raiseForStatus(res: Response, fallback: string): Promise<void> {\n if (res.ok) return;\n let detail = \"\";\n try {\n detail = await res.text();\n } catch {\n detail = \"\";\n }\n const base = DEFAULT_MESSAGES[res.status] ?? fallback;\n throw new AgentApiError(\n detail ? `${base} (${detail.slice(0, 500)})` : base,\n res.status,\n res.headers.get(\"x-request-id\"),\n detail,\n );\n}\n",
6
- "// A `fetch`-based Server-Sent Events reader. Not `EventSource`: that can't\n// attach an Authorization header, which every stream here requires.\n//\n// Runtime-agnostic on purpose — `fetch`, `ReadableStream` and `AbortController`\n// only, no DOM. Exported as its own entry point (`@cubos/agent-sdk/sse`) so the\n// operator dashboard can reuse it without adopting the rest of the client.\n\nimport { raiseForStatus } from \"./errors.js\";\n\n/** Just the call signature, not `typeof fetch` — that also demands runtime\n * extras (Bun's `preconnect`, undici's statics) a caller's wrapper won't have. */\nexport type FetchLike = (\n input: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n body?: string | FormData;\n signal?: AbortSignal;\n },\n) => Promise<Response>;\n\nexport interface SseOptions<T> {\n url: string;\n /**\n * Only frames with one of these `event:` names are delivered; the rest are\n * dropped. Several names on one connection is how a stream keeps two kinds of\n * frame in a single order — split across two connections there is none, and a\n * client cannot tell which came first.\n */\n event: string | string[];\n onEvent: (data: T, event: string) => void;\n signal: AbortSignal;\n /** Called before each (re)connect, so the caller can mint a fresh token. */\n headers?: () => Promise<Record<string, string>> | Record<string, string>;\n /** Called once per successful connect, before any frame is delivered. The\n * hook a caller needs to catch up on state the stream won't replay: it fires\n * on every reconnect too, so a gap the backoff swallowed is covered as\n * well. Not awaited — a slow catch-up must not stall frame delivery. */\n onOpen?: () => void;\n /** Resume cursor for the first connect. Later reconnects use the last `id:`\n * the server actually sent. */\n lastEventId?: string;\n fetchImpl?: FetchLike;\n onError?: (err: unknown) => void;\n}\n\nconst MAX_BACKOFF_MS = 30_000;\n\n/** Marks an error the reconnect loop must not swallow. */\nclass Fatal extends Error {\n override readonly cause: unknown;\n constructor(cause: unknown) {\n super(\"fatal stream error\");\n this.cause = cause;\n }\n}\n\n/**\n * Reads `url` until `signal` aborts, reconnecting through any drop — clean\n * close from the server included, since intermediaries (Cloudflare et al.)\n * close idle SSE connections without warning and the caller would otherwise\n * silently stop receiving.\n *\n * `Last-Event-ID` is replayed from the last frame the server sent, so the\n * backend's catch-up query fills whatever the gap swallowed. 4xx ends the loop\n * — a bad token or a deleted conversation won't fix itself by retrying.\n */\nexport async function readSse<T>(opts: SseOptions<T>): Promise<void> {\n const doFetch = opts.fetchImpl ?? globalThis.fetch;\n let lastEventId = opts.lastEventId;\n let attempt = 0;\n\n while (!opts.signal.aborted) {\n let madeProgress = false;\n try {\n const headers: Record<string, string> = {\n ...(await opts.headers?.()),\n Accept: \"text/event-stream\",\n };\n if (lastEventId !== undefined) headers[\"Last-Event-ID\"] = lastEventId;\n\n const res = await doFetch(opts.url, { headers, signal: opts.signal });\n if (opts.signal.aborted) return;\n if (res.ok && res.body) opts.onOpen?.();\n\n if (!res.ok || !res.body) {\n if (res.status >= 400 && res.status < 500) {\n // Wrapped so the catch below can tell it apart from a transient\n // failure and rethrow instead of reconnecting forever.\n await raiseForStatus(res, `Could not open ${opts.url}.`).catch((err) => {\n throw new Fatal(err);\n });\n return;\n }\n throw new Error(`stream open failed with HTTP ${res.status}`);\n }\n\n for await (const frame of frames(res.body, opts.signal)) {\n const parsed = parseFrame<T>(frame, opts.event);\n if (parsed === null) continue;\n if (parsed.id !== null) lastEventId = parsed.id;\n opts.onEvent(parsed.data, parsed.event);\n madeProgress = true;\n }\n } catch (err) {\n if (opts.signal.aborted) return;\n // A bad token or a deleted conversation won't fix itself by retrying.\n if (err instanceof Fatal) throw err.cause;\n // Everything else is transient (network, 5xx, proxy hangup) — report and\n // back off rather than end the subscription.\n opts.onError?.(err);\n }\n\n if (opts.signal.aborted) return;\n\n // Any delivered frame resets the backoff: a long-lived stream that did real\n // work and then dropped should come back fast, not wait out the ceiling.\n if (madeProgress) attempt = 0;\n const delayMs = Math.min(MAX_BACKOFF_MS, 1_000 * 2 ** attempt);\n attempt += 1;\n await sleep(delayMs, opts.signal);\n }\n}\n\nasync function* frames(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n): AsyncGenerator<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) return;\n buffer += decoder.decode(value, { stream: true });\n for (;;) {\n const sep = buffer.indexOf(\"\\n\\n\");\n if (sep === -1) break;\n yield buffer.slice(0, sep);\n buffer = buffer.slice(sep + 2);\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n}\n\nexport function parseFrame<T>(\n frame: string,\n expectedEvent: string | string[],\n): { data: T; id: string | null; event: string } | null {\n let dataLine: string | null = null;\n let id: string | null = null;\n let eventName = \"message\";\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\":\")) continue;\n if (line.startsWith(\"data:\")) dataLine = line.slice(5).trimStart();\n else if (line.startsWith(\"event:\")) eventName = line.slice(6).trim();\n else if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n }\n const wanted =\n typeof expectedEvent === \"string\"\n ? eventName === expectedEvent\n : expectedEvent.includes(eventName);\n if (!wanted || dataLine === null) return null;\n try {\n return { data: JSON.parse(dataLine) as T, id, event: eventName };\n } catch {\n return null;\n }\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const onAbort = () => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n"
6
+ "// A `fetch`-based Server-Sent Events reader. Not `EventSource`: that can't\n// attach an Authorization header, which every stream here requires.\n//\n// Runtime-agnostic on purpose — `fetch`, `ReadableStream` and `AbortController`\n// only, no DOM. Exported as its own entry point (`@cubos/agent-sdk/sse`) so the\n// operator dashboard can reuse it without adopting the rest of the client.\n\nimport { raiseForStatus } from \"./errors.js\";\n\n/** Just the call signature, not `typeof fetch` — that also demands runtime\n * extras (Bun's `preconnect`, undici's statics) a caller's wrapper won't have. */\nexport type FetchLike = (\n input: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n body?: string | FormData;\n signal?: AbortSignal;\n },\n) => Promise<Response>;\n\nexport interface SseOptions<T> {\n url: string;\n /**\n * Only frames with one of these `event:` names are delivered; the rest are\n * dropped. Several names on one connection is how a stream keeps two kinds of\n * frame in a single order — split across two connections there is none, and a\n * client cannot tell which came first.\n */\n event: string | string[];\n onEvent: (data: T, event: string) => void;\n signal: AbortSignal;\n /** Called before each (re)connect, so the caller can mint a fresh token.\n * `forceRefresh` is set on the one immediate retry that follows a 401 — a\n * caller that caches a token must bypass the cache when it sees it, or the\n * retry replays the rejected credential and the stream dies for good. */\n headers?: (opts: {\n forceRefresh: boolean;\n }) => Promise<Record<string, string>> | Record<string, string>;\n /** Called once per successful connect, before any frame is delivered. The\n * hook a caller needs to catch up on state the stream won't replay: it fires\n * on every reconnect too, so a gap the backoff swallowed is covered as\n * well. Not awaited — a slow catch-up must not stall frame delivery. */\n onOpen?: () => void;\n /** Resume cursor for the first connect. Later reconnects use the last `id:`\n * the server actually sent. */\n lastEventId?: string;\n fetchImpl?: FetchLike;\n /**\n * Reconnect when this many milliseconds pass with no bytes at all — not even\n * a keep-alive comment. Defaults to `DEFAULT_IDLE_TIMEOUT_MS`; `0` disables.\n *\n * A half-open socket (a phone leaving the background, a proxy that dropped\n * the connection without telling either end) leaves `read()` waiting forever,\n * with nothing for the reconnect loop below to react to. The server sends a\n * comment every 15s, so silence past twice that is the connection being gone\n * rather than the agent being quiet.\n */\n idleTimeoutMs?: number;\n /** Every failed attempt, transient or fatal. The loop is already reconnecting\n * when this fires unless the promise also rejects. */\n onError?: (err: unknown) => void;\n}\n\nconst MAX_BACKOFF_MS = 30_000;\n\n/** Twice the server's 15s keep-alive interval: one comment may be lost to a\n * hiccup without the connection being gone, two in a row means it is. */\nexport const DEFAULT_IDLE_TIMEOUT_MS = 30_000;\n\n/** Marks an error the reconnect loop must not swallow. */\nclass Fatal extends Error {\n override readonly cause: unknown;\n constructor(cause: unknown) {\n super(\"fatal stream error\");\n this.cause = cause;\n }\n}\n\n/** Raised when the watchdog trips, so a caller logging `onError` can tell a\n * connection that went silent from one that failed outright. */\nexport class SseIdleTimeout extends Error {\n constructor(url: string, ms: number) {\n super(`Stream ${url} sent nothing for ${ms}ms — reconnecting.`);\n this.name = \"SseIdleTimeout\";\n }\n}\n\n/**\n * Reads `url` until `signal` aborts, reconnecting through any drop — clean\n * close from the server included, since intermediaries (Cloudflare et al.)\n * close idle SSE connections without warning and the caller would otherwise\n * silently stop receiving.\n *\n * `Last-Event-ID` is replayed from the last frame the server sent, so the\n * backend's catch-up query fills whatever the gap swallowed. 4xx ends the loop\n * — a deleted conversation won't fix itself by retrying — with one exception: a\n * 401 buys one immediate reconnect with `forceRefresh`, because a short-lived\n * token expiring under a stream that outlives it is the expected case, not a\n * misconfiguration. Only after that second rejection does the promise reject.\n *\n * A connection that goes silent past `idleTimeoutMs` is dropped and reopened:\n * see that option for why waiting on `read()` forever is not an option.\n */\nexport async function readSse<T>(opts: SseOptions<T>): Promise<void> {\n const doFetch = opts.fetchImpl ?? globalThis.fetch;\n const idleMs = opts.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;\n let lastEventId = opts.lastEventId;\n let attempt = 0;\n // Set by a 401 and consumed by the connect that follows it, so the retry is\n // the only attempt that pays for a freshly minted token.\n let refreshing = false;\n\n while (!opts.signal.aborted) {\n let madeProgress = false;\n // Aborts this connection alone — the watchdog must be able to drop a dead\n // socket without ending the subscription the caller's signal owns.\n const connection = new AbortController();\n const unlink = forward(opts.signal, connection);\n let idleTimer: ReturnType<typeof setTimeout> | undefined;\n let wentIdle = false;\n const armIdle = () => {\n if (idleMs <= 0) return;\n clearTimeout(idleTimer);\n idleTimer = setTimeout(() => {\n wentIdle = true;\n connection.abort();\n }, idleMs);\n };\n\n try {\n const headers: Record<string, string> = {\n ...(await opts.headers?.({ forceRefresh: refreshing })),\n Accept: \"text/event-stream\",\n };\n if (lastEventId !== undefined) headers[\"Last-Event-ID\"] = lastEventId;\n\n // Armed before the fetch: a connect that never answers is as dead as one\n // that stops mid-stream, and nothing else bounds it.\n armIdle();\n const res = await doFetch(opts.url, { headers, signal: connection.signal });\n if (opts.signal.aborted) return;\n if (res.ok && res.body) {\n refreshing = false;\n opts.onOpen?.();\n }\n\n if (!res.ok || !res.body) {\n // One immediate retry, no backoff: a token that expired between minting\n // and this connect is the expected case for a stream that outlives its\n // TTL, and `headers` is the only thing that can produce a new one. A\n // credential that is simply wrong takes the fatal path on the retry.\n if (res.status === 401 && opts.headers && !refreshing) {\n refreshing = true;\n continue;\n }\n if (res.status >= 400 && res.status < 500) {\n // Wrapped so the catch below can tell it apart from a transient\n // failure and rethrow instead of reconnecting forever.\n await raiseForStatus(res, `Could not open ${opts.url}.`).catch((err) => {\n throw new Fatal(err);\n });\n return;\n }\n throw new Error(`stream open failed with HTTP ${res.status}`);\n }\n\n for await (const frame of frames(res.body, connection.signal, armIdle)) {\n const parsed = parseFrame<T>(frame, opts.event);\n if (parsed === null) continue;\n if (parsed.id !== null) lastEventId = parsed.id;\n opts.onEvent(parsed.data, parsed.event);\n madeProgress = true;\n }\n if (wentIdle) throw new SseIdleTimeout(opts.url, idleMs);\n } catch (err) {\n if (opts.signal.aborted) return;\n // A deleted conversation, or a credential a refresh didn't fix.\n if (err instanceof Fatal) throw err.cause;\n // Everything else is transient (network, 5xx, proxy hangup, a socket that\n // went silent) — report and back off rather than end the subscription.\n opts.onError?.(wentIdle ? new SseIdleTimeout(opts.url, idleMs) : err);\n } finally {\n clearTimeout(idleTimer);\n unlink();\n // Nothing below this point reads from the body; letting it hang open\n // would leak a connection per reconnect.\n connection.abort();\n }\n\n if (opts.signal.aborted) return;\n\n // Any delivered frame resets the backoff: a long-lived stream that did real\n // work and then dropped should come back fast, not wait out the ceiling.\n if (madeProgress) attempt = 0;\n const delayMs = Math.min(MAX_BACKOFF_MS, 1_000 * 2 ** attempt);\n attempt += 1;\n await sleep(delayMs, opts.signal);\n }\n}\n\n/** `onRead` fires for every chunk the socket delivers, keep-alive comments\n * included — the watchdog is asking whether the connection is alive, which is\n * not the same question as whether a frame the caller wanted came through. */\nasync function* frames(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n onRead: () => void,\n): AsyncGenerator<string> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) return;\n onRead();\n buffer += decoder.decode(value, { stream: true });\n for (;;) {\n const sep = buffer.indexOf(\"\\n\\n\");\n if (sep === -1) break;\n yield buffer.slice(0, sep);\n buffer = buffer.slice(sep + 2);\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n}\n\nexport function parseFrame<T>(\n frame: string,\n expectedEvent: string | string[],\n): { data: T; id: string | null; event: string } | null {\n let dataLine: string | null = null;\n let id: string | null = null;\n let eventName = \"message\";\n for (const line of frame.split(\"\\n\")) {\n if (line.startsWith(\":\")) continue;\n if (line.startsWith(\"data:\")) dataLine = line.slice(5).trimStart();\n else if (line.startsWith(\"event:\")) eventName = line.slice(6).trim();\n else if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n }\n const wanted =\n typeof expectedEvent === \"string\"\n ? eventName === expectedEvent\n : expectedEvent.includes(eventName);\n if (!wanted || dataLine === null) return null;\n try {\n return { data: JSON.parse(dataLine) as T, id, event: eventName };\n } catch {\n return null;\n }\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n const onAbort = () => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\n/** Aborts `child` when `outer` does, and hands back the unsubscribe — without\n * it every reconnect would leave another listener on a signal that lives as\n * long as the subscription. */\nfunction forward(outer: AbortSignal, child: AbortController): () => void {\n const onAbort = () => child.abort();\n if (outer.aborted) child.abort();\n else outer.addEventListener(\"abort\", onAbort, { once: true });\n return () => outer.removeEventListener(\"abort\", onAbort);\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "85857292E5DF4F6B64756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "24E2FA6F4632B4F664756E2164756E21",
10
10
  "names": []
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cubos/agent-sdk",
3
- "version": "0.0.1140428",
3
+ "version": "0.0.1140658",
4
4
  "type": "module",
5
5
  "description": "Client for the Cubos Agent conversation API. Runs anywhere fetch does.",
6
6
  "license": "SEE LICENSE IN LICENSE",