@cubos/agent-sdk 0.0.1154888 → 0.0.1154905
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/admin/index.d.ts +3 -1
- package/dist/admin/users.d.ts +100 -0
- package/dist/errors.d.ts +38 -1
- package/dist/generated/schema.d.ts +512 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +30 -1
- package/dist/index.js.map +5 -5
- package/dist/sse.js +13 -1
- package/dist/sse.js.map +3 -3
- package/package.json +1 -1
package/dist/sse.js
CHANGED
|
@@ -36,6 +36,18 @@ class AgentApiError extends AgentError {
|
|
|
36
36
|
get isRetryable() {
|
|
37
37
|
return this.status === 429 || this.status >= 500;
|
|
38
38
|
}
|
|
39
|
+
get overBudget() {
|
|
40
|
+
if (this.status !== 402)
|
|
41
|
+
return null;
|
|
42
|
+
const b = this.json();
|
|
43
|
+
if (b?.error !== "over_budget" || !b.period || !b.resets_at)
|
|
44
|
+
return null;
|
|
45
|
+
return {
|
|
46
|
+
period: b.period,
|
|
47
|
+
resetsAt: b.resets_at,
|
|
48
|
+
message: b.message ?? "Spending limit reached."
|
|
49
|
+
};
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
class AgentConfigError extends AgentError {
|
|
@@ -269,5 +281,5 @@ export {
|
|
|
269
281
|
readSse
|
|
270
282
|
};
|
|
271
283
|
|
|
272
|
-
//# debugId=
|
|
284
|
+
//# debugId=F98752A3B80C0CA564756E2164756E21
|
|
273
285
|
//# sourceMappingURL=sse.js.map
|
package/dist/sse.js.map
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/errors.ts", "../src/sse.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
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
|
|
5
|
+
"/**\n * A spend ceiling was reached. The body of a 402, parsed.\n *\n * Carries no amounts, deliberately. The dollar figures behind a ceiling are\n * the operator's accounting: most products put their own layer over this —\n * credits, a plan tier, a quota in requests — so \"you spent 0.055 of 0.05\"\n * would be a unit the user was never sold in. Those figures live on the admin\n * surface, behind `users:read`.\n *\n * What is here is what an app can act on: `message`, authored by the tenant\n * and therefore already speaking in whatever unit they sell; the window that\n * tripped; and when it lifts.\n */\nexport interface OverBudget {\n period: \"hour\" | \"day\" | \"week\" | \"month\";\n /** When the window turns over and access returns, as an ISO instant. */\n resetsAt: string;\n /** Ready to show, already naming the window and the reset. */\n message: string;\n}\n\n/** 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 /**\n * Worth retrying after a pause: the server is overloaded or briefly down.\n *\n * Note what is absent. A 402 is *not* retryable here, deliberately: the\n * window it names is hours or days away, so retrying is pointless and\n * retrying automatically would spend the user's backoff budget on a wall\n * that is not going to move.\n */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n\n /**\n * The spend ceiling this request hit, or `null` when the failure was\n * something else.\n *\n * Distinct from `isAuthError` on purpose — a blocked user (403) and a user\n * over budget (402) look the same to a client that only checks \"was I\n * refused\", and they are opposite situations: one needs an operator, the\n * other needs a clock.\n */\n get overBudget(): OverBudget | null {\n if (this.status !== 402) return null;\n const b = this.json<{\n error?: string;\n period?: OverBudget[\"period\"];\n resets_at?: string;\n message?: string;\n }>();\n if (b?.error !== \"over_budget\" || !b.period || !b.resets_at) return null;\n return {\n period: b.period,\n resetsAt: b.resets_at,\n message: b.message ?? \"Spending limit reached.\",\n };\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\n/**\n * Milliseconds from a `Retry-After`, which is either a delta in seconds or an\n * HTTP date. Returns null when absent or unusable, so the caller can decide not\n * to retry rather than guess an interval. Shared by the request retry and the\n * stream reconnect, which honour the same header from the same limiter.\n */\nexport function parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const seconds = Number(header.trim());\n if (Number.isFinite(seconds)) return Math.max(0, seconds * 1000);\n const date = Date.parse(header);\n if (Number.isNaN(date)) return null;\n return Math.max(0, date - Date.now());\n}\n",
|
|
6
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 { parseRetryAfter, 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 /**\n * The cursor as a shared cell instead: read before every connect and written\n * after every frame, so something else delivering the same log — a poll that\n * runs while a connection is unproven — can advance it, and the next connect\n * asks for what neither has seen rather than replaying what the other did.\n * Takes precedence over `lastEventId`.\n */\n cursor?: { lastEventId?: string };\n /** Every time a connection ends, for whatever reason, before the wait that\n * precedes the next attempt. The counterpart of `onOpen`: between the two a\n * connection was live, and outside them nothing is being received. */\n onClose?: () => void;\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 two exceptions.\n * A 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 * And a 429 is a refusal, not a verdict: the user's budget or their cap on open\n * streams is full, and the server says when to come back — so the loop waits\n * out `Retry-After` and tries again, rather than ending a subscription over a\n * limit that clears in seconds.\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 const cursor = opts.cursor ?? { 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 // Set by a 429 from the server's own `Retry-After`; overrides the\n // exponential backoff for the wait that follows.\n let retryAfterMs: number | null = null;\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 (cursor.lastEventId !== undefined) headers[\"Last-Event-ID\"] = cursor.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 === 429) {\n // Transient by definition, and the one 4xx an app can hit by\n // doing nothing wrong: a user with one tab too many is over the\n // per-user cap on open streams, and each tab's stream would die\n // for good here while the cap clears the moment any tab closes.\n // Without a usable header the ceiling is the wait — the limiter\n // always sends one, so that is the odd proxy, not the server.\n retryAfterMs = Math.min(\n MAX_BACKOFF_MS,\n parseRetryAfter(res.headers.get(\"retry-after\")) ?? MAX_BACKOFF_MS,\n );\n await raiseForStatus(res, `Could not open ${opts.url}.`);\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) cursor.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 opts.onClose?.();\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 = retryAfterMs ?? 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": ";
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "F98752A3B80C0CA564756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|