summaryrefslogtreecommitdiffhomepage
path: root/packages/sdk/js/src/gen/core
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-08-22 18:30:25 -0400
committerDax Raad <[email protected]>2025-08-22 18:30:25 -0400
commit0f1697b2ab6e2401d0a3534323bb75d5002e8e32 (patch)
tree6350dcd0319802e8ff373c610909c020a1e52e71 /packages/sdk/js/src/gen/core
parent6e626afdcbfe7bebd5799fdfea342c15ab2151bb (diff)
downloadopencode-0f1697b2ab6e2401d0a3534323bb75d5002e8e32.tar.gz
opencode-0f1697b2ab6e2401d0a3534323bb75d5002e8e32.zip
add sse streaming to sdk
Diffstat (limited to 'packages/sdk/js/src/gen/core')
-rw-r--r--packages/sdk/js/src/gen/core/auth.gen.ts (renamed from packages/sdk/js/src/gen/core/auth.ts)2
-rw-r--r--packages/sdk/js/src/gen/core/bodySerializer.gen.ts (renamed from packages/sdk/js/src/gen/core/bodySerializer.ts)6
-rw-r--r--packages/sdk/js/src/gen/core/params.gen.ts (renamed from packages/sdk/js/src/gen/core/params.ts)2
-rw-r--r--packages/sdk/js/src/gen/core/pathSerializer.gen.ts (renamed from packages/sdk/js/src/gen/core/pathSerializer.ts)2
-rw-r--r--packages/sdk/js/src/gen/core/serverSentEvents.gen.ts210
-rw-r--r--packages/sdk/js/src/gen/core/types.gen.ts (renamed from packages/sdk/js/src/gen/core/types.ts)6
-rw-r--r--packages/sdk/js/src/gen/core/utils.gen.ts109
7 files changed, 334 insertions, 3 deletions
diff --git a/packages/sdk/js/src/gen/core/auth.ts b/packages/sdk/js/src/gen/core/auth.gen.ts
index e496d4557..bc7b230f4 100644
--- a/packages/sdk/js/src/gen/core/auth.ts
+++ b/packages/sdk/js/src/gen/core/auth.gen.ts
@@ -1,3 +1,5 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
export type AuthToken = string | undefined
export interface Auth {
diff --git a/packages/sdk/js/src/gen/core/bodySerializer.ts b/packages/sdk/js/src/gen/core/bodySerializer.gen.ts
index 8a4a13410..066061605 100644
--- a/packages/sdk/js/src/gen/core/bodySerializer.ts
+++ b/packages/sdk/js/src/gen/core/bodySerializer.gen.ts
@@ -1,4 +1,6 @@
-import type { ArrayStyle, ObjectStyle, SerializerOptions } from "./pathSerializer.js"
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { ArrayStyle, ObjectStyle, SerializerOptions } from "./pathSerializer.gen.js"
export type QuerySerializer = (query: Record<string, unknown>) => string
@@ -13,6 +15,8 @@ export interface QuerySerializerOptions {
const serializeFormDataPair = (data: FormData, key: string, value: unknown): void => {
if (typeof value === "string" || value instanceof Blob) {
data.append(key, value)
+ } else if (value instanceof Date) {
+ data.append(key, value.toISOString())
} else {
data.append(key, JSON.stringify(value))
}
diff --git a/packages/sdk/js/src/gen/core/params.ts b/packages/sdk/js/src/gen/core/params.gen.ts
index 0a09619d1..68ad1a778 100644
--- a/packages/sdk/js/src/gen/core/params.ts
+++ b/packages/sdk/js/src/gen/core/params.gen.ts
@@ -1,3 +1,5 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
type Slot = "body" | "headers" | "path" | "query"
export type Field =
diff --git a/packages/sdk/js/src/gen/core/pathSerializer.ts b/packages/sdk/js/src/gen/core/pathSerializer.gen.ts
index 1e27c8d18..96be3bc5a 100644
--- a/packages/sdk/js/src/gen/core/pathSerializer.ts
+++ b/packages/sdk/js/src/gen/core/pathSerializer.gen.ts
@@ -1,3 +1,5 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
interface SerializeOptions<T> extends SerializePrimitiveOptions, SerializerOptions<T> {}
interface SerializePrimitiveOptions {
diff --git a/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts
new file mode 100644
index 000000000..8f7fac549
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/serverSentEvents.gen.ts
@@ -0,0 +1,210 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { Config } from "./types.gen.js"
+
+export type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, "method"> &
+ Pick<Config, "method" | "responseTransformer" | "responseValidator"> & {
+ /**
+ * Callback invoked when a network or parsing error occurs during streaming.
+ *
+ * This option applies only if the endpoint returns a stream of events.
+ *
+ * @param error The error that occurred.
+ */
+ onSseError?: (error: unknown) => void
+ /**
+ * Callback invoked when an event is streamed from the server.
+ *
+ * This option applies only if the endpoint returns a stream of events.
+ *
+ * @param event Event streamed from the server.
+ * @returns Nothing (void).
+ */
+ onSseEvent?: (event: StreamEvent<TData>) => void
+ /**
+ * Default retry delay in milliseconds.
+ *
+ * This option applies only if the endpoint returns a stream of events.
+ *
+ * @default 3000
+ */
+ sseDefaultRetryDelay?: number
+ /**
+ * Maximum number of retry attempts before giving up.
+ */
+ sseMaxRetryAttempts?: number
+ /**
+ * Maximum retry delay in milliseconds.
+ *
+ * Applies only when exponential backoff is used.
+ *
+ * This option applies only if the endpoint returns a stream of events.
+ *
+ * @default 30000
+ */
+ sseMaxRetryDelay?: number
+ /**
+ * Optional sleep function for retry backoff.
+ *
+ * Defaults to using `setTimeout`.
+ */
+ sseSleepFn?: (ms: number) => Promise<void>
+ url: string
+ }
+
+export interface StreamEvent<TData = unknown> {
+ data: TData
+ event?: string
+ id?: string
+ retry?: number
+}
+
+export type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unknown> = {
+ stream: AsyncGenerator<TData extends Record<string, unknown> ? TData[keyof TData] : TData, TReturn, TNext>
+}
+
+export const createSseClient = <TData = unknown>({
+ onSseError,
+ onSseEvent,
+ responseTransformer,
+ responseValidator,
+ sseDefaultRetryDelay,
+ sseMaxRetryAttempts,
+ sseMaxRetryDelay,
+ sseSleepFn,
+ url,
+ ...options
+}: ServerSentEventsOptions): ServerSentEventsResult<TData> => {
+ let lastEventId: string | undefined
+
+ const sleep = sseSleepFn ?? ((ms: number) => new Promise((resolve) => setTimeout(resolve, ms)))
+
+ const createStream = async function* () {
+ let retryDelay: number = sseDefaultRetryDelay ?? 3000
+ let attempt = 0
+ const signal = options.signal ?? new AbortController().signal
+
+ while (true) {
+ if (signal.aborted) break
+
+ attempt++
+
+ const headers =
+ options.headers instanceof Headers
+ ? options.headers
+ : new Headers(options.headers as Record<string, string> | undefined)
+
+ if (lastEventId !== undefined) {
+ headers.set("Last-Event-ID", lastEventId)
+ }
+
+ try {
+ const response = await fetch(url, { ...options, headers, signal })
+
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`)
+
+ if (!response.body) throw new Error("No body in SSE response")
+
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader()
+
+ let buffer = ""
+
+ const abortHandler = () => {
+ try {
+ reader.cancel()
+ } catch {
+ // noop
+ }
+ }
+
+ signal.addEventListener("abort", abortHandler)
+
+ try {
+ while (true) {
+ const { done, value } = await reader.read()
+ if (done) break
+ buffer += value
+
+ const chunks = buffer.split("\n\n")
+ buffer = chunks.pop() ?? ""
+
+ for (const chunk of chunks) {
+ const lines = chunk.split("\n")
+ const dataLines: Array<string> = []
+ let eventName: string | undefined
+
+ for (const line of lines) {
+ if (line.startsWith("data:")) {
+ dataLines.push(line.replace(/^data:\s*/, ""))
+ } else if (line.startsWith("event:")) {
+ eventName = line.replace(/^event:\s*/, "")
+ } else if (line.startsWith("id:")) {
+ lastEventId = line.replace(/^id:\s*/, "")
+ } else if (line.startsWith("retry:")) {
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10)
+ if (!Number.isNaN(parsed)) {
+ retryDelay = parsed
+ }
+ }
+ }
+
+ let data: unknown
+ let parsedJson = false
+
+ if (dataLines.length) {
+ const rawData = dataLines.join("\n")
+ try {
+ data = JSON.parse(rawData)
+ parsedJson = true
+ } catch {
+ data = rawData
+ }
+ }
+
+ if (parsedJson) {
+ if (responseValidator) {
+ await responseValidator(data)
+ }
+
+ if (responseTransformer) {
+ data = await responseTransformer(data)
+ }
+ }
+
+ onSseEvent?.({
+ data,
+ event: eventName,
+ id: lastEventId,
+ retry: retryDelay,
+ })
+
+ if (dataLines.length) {
+ yield data as any
+ }
+ }
+ }
+ } finally {
+ signal.removeEventListener("abort", abortHandler)
+ reader.releaseLock()
+ }
+
+ break // exit loop on normal completion
+ } catch (error) {
+ // connection failed or aborted; retry after delay
+ onSseError?.(error)
+
+ if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) {
+ break // stop after firing error
+ }
+
+ // exponential backoff: double retry each attempt, cap at 30s
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000)
+ await sleep(backoff)
+ }
+ }
+ }
+
+ const stream = createStream()
+
+ return { stream }
+}
diff --git a/packages/sdk/js/src/gen/core/types.ts b/packages/sdk/js/src/gen/core/types.gen.ts
index 3a12e74c6..16408b2d0 100644
--- a/packages/sdk/js/src/gen/core/types.ts
+++ b/packages/sdk/js/src/gen/core/types.gen.ts
@@ -1,5 +1,7 @@
-import type { Auth, AuthToken } from "./auth.js"
-import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.js"
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { Auth, AuthToken } from "./auth.gen.js"
+import type { BodySerializer, QuerySerializer, QuerySerializerOptions } from "./bodySerializer.gen.js"
export interface Client<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never> {
/**
diff --git a/packages/sdk/js/src/gen/core/utils.gen.ts b/packages/sdk/js/src/gen/core/utils.gen.ts
new file mode 100644
index 000000000..be18c608a
--- /dev/null
+++ b/packages/sdk/js/src/gen/core/utils.gen.ts
@@ -0,0 +1,109 @@
+// This file is auto-generated by @hey-api/openapi-ts
+
+import type { QuerySerializer } from "./bodySerializer.gen.js"
+import {
+ type ArraySeparatorStyle,
+ serializeArrayParam,
+ serializeObjectParam,
+ serializePrimitiveParam,
+} from "./pathSerializer.gen.js"
+
+export interface PathSerializer {
+ path: Record<string, unknown>
+ url: string
+}
+
+export const PATH_PARAM_RE = /\{[^{}]+\}/g
+
+export const defaultPathSerializer = ({ path, url: _url }: PathSerializer) => {
+ let url = _url
+ const matches = _url.match(PATH_PARAM_RE)
+ if (matches) {
+ for (const match of matches) {
+ let explode = false
+ let name = match.substring(1, match.length - 1)
+ let style: ArraySeparatorStyle = "simple"
+
+ if (name.endsWith("*")) {
+ explode = true
+ name = name.substring(0, name.length - 1)
+ }
+
+ if (name.startsWith(".")) {
+ name = name.substring(1)
+ style = "label"
+ } else if (name.startsWith(";")) {
+ name = name.substring(1)
+ style = "matrix"
+ }
+
+ const value = path[name]
+
+ if (value === undefined || value === null) {
+ continue
+ }
+
+ if (Array.isArray(value)) {
+ url = url.replace(match, serializeArrayParam({ explode, name, style, value }))
+ continue
+ }
+
+ if (typeof value === "object") {
+ url = url.replace(
+ match,
+ serializeObjectParam({
+ explode,
+ name,
+ style,
+ value: value as Record<string, unknown>,
+ valueOnly: true,
+ }),
+ )
+ continue
+ }
+
+ if (style === "matrix") {
+ url = url.replace(
+ match,
+ `;${serializePrimitiveParam({
+ name,
+ value: value as string,
+ })}`,
+ )
+ continue
+ }
+
+ const replaceValue = encodeURIComponent(style === "label" ? `.${value as string}` : (value as string))
+ url = url.replace(match, replaceValue)
+ }
+ }
+ return url
+}
+
+export const getUrl = ({
+ baseUrl,
+ path,
+ query,
+ querySerializer,
+ url: _url,
+}: {
+ baseUrl?: string
+ path?: Record<string, unknown>
+ query?: Record<string, unknown>
+ querySerializer: QuerySerializer
+ url: string
+}) => {
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`
+ let url = (baseUrl ?? "") + pathUrl
+ if (path) {
+ url = defaultPathSerializer({ path, url })
+ }
+ let search = query ? querySerializer(query) : ""
+ if (search.startsWith("?")) {
+ search = search.substring(1)
+ }
+ if (search) {
+ url += `?${search}`
+ }
+ return url
+}