@durable-streams/client 0.1.0 → 0.1.1
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/LICENSE +21 -0
- package/package.json +21 -7
- package/dist/index.cjs +0 -1172
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -627
- package/dist/index.js.map +0 -1
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/stream.ts","../src/error.ts","../src/constants.ts","../src/fetch.ts"],"sourcesContent":["/**\n * DurableStream - A handle to a remote durable stream.\n *\n * Following the Electric Durable Stream Protocol specification.\n */\n\nimport { fetchEventSource } from \"@microsoft/fetch-event-source\"\nimport {\n DurableStreamError,\n FetchBackoffAbortError,\n InvalidSignalError,\n MissingStreamUrlError,\n} from \"./error\"\nimport {\n CURSOR_QUERY_PARAM,\n LIVE_QUERY_PARAM,\n OFFSET_QUERY_PARAM,\n SSE_COMPATIBLE_CONTENT_TYPES,\n STREAM_CURSOR_HEADER,\n STREAM_EXPIRES_AT_HEADER,\n STREAM_OFFSET_HEADER,\n STREAM_SEQ_HEADER,\n STREAM_TTL_HEADER,\n STREAM_UP_TO_DATE_HEADER,\n} from \"./constants\"\nimport {\n BackoffDefaults,\n chainAborter,\n createFetchWithBackoff,\n createFetchWithConsumedBody,\n} from \"./fetch\"\nimport type { EventSourceMessage } from \"@microsoft/fetch-event-source\"\nimport type {\n AppendOptions,\n CreateOptions,\n HeadResult,\n MaybePromise,\n Offset,\n ReadOptions,\n ReadResult,\n StreamChunk,\n StreamErrorHandler,\n StreamOptions,\n} from \"./types\"\n\nimport type { BackoffOptions } from \"./fetch\"\n\n/**\n * Options for DurableStream constructor.\n */\nexport interface DurableStreamOptions extends StreamOptions {\n /**\n * Backoff options for retry behavior.\n */\n backoffOptions?: BackoffOptions\n\n /**\n * Error handler for recoverable errors.\n *\n * **Automatic retries**: The client automatically retries 5xx server errors, network\n * errors, and 429 rate limits with exponential backoff. The `onError` callback is\n * only invoked after these automatic retries are exhausted, or for non-retryable errors.\n *\n * **Return value behavior** (following Electric client pattern):\n * - Return `{}` to retry with the same params/headers\n * - Return `{ params }` to retry with merged params\n * - Return `{ headers }` to retry with merged headers\n * - Return `void`/`undefined` to stop the stream and propagate the error\n *\n * @example\n * ```typescript\n * // Refresh auth token on 401\n * onError: async (error) => {\n * if (error instanceof FetchError && error.status === 401) {\n * const newToken = await refreshAuthToken()\n * return { headers: { Authorization: `Bearer ${newToken}` } }\n * }\n * }\n * ```\n */\n onError?: StreamErrorHandler\n}\n\n/**\n * A handle to a remote durable stream.\n *\n * This is a lightweight, reusable handle - not a persistent connection.\n * It does not automatically start reading or listening.\n * Create sessions as needed via read(), follow(), or toReadableStream().\n *\n * @example\n * ```typescript\n * // Create a handle without any network IO\n * const stream = new DurableStream({\n * url: \"https://streams.example.com/my-stream\",\n * auth: { token: \"my-token\" }\n * });\n *\n * // One-shot read\n * const result = await stream.read({ offset: savedOffset });\n *\n * // Follow for live updates\n * for await (const chunk of stream.follow()) {\n * console.log(new TextDecoder().decode(chunk.data));\n * }\n * ```\n */\nexport class DurableStream {\n /**\n * The URL of the durable stream.\n */\n readonly url: string\n\n /**\n * The content type of the stream (populated after connect/head/read).\n */\n contentType?: string\n\n #options: DurableStreamOptions\n readonly #fetchClient: typeof fetch\n readonly #sseFetchClient: typeof fetch\n #onError?: StreamErrorHandler\n\n /**\n * Create a cold handle to a stream.\n * No network IO is performed by the constructor.\n */\n constructor(opts: DurableStreamOptions) {\n validateOptions(opts)\n this.url = opts.url\n this.#options = opts\n this.#onError = opts.onError\n\n const baseFetchClient =\n opts.fetch ?? ((...args: Parameters<typeof fetch>) => fetch(...args))\n\n const backOffOpts = {\n ...(opts.backoffOptions ?? BackoffDefaults),\n }\n\n const fetchWithBackoffClient = createFetchWithBackoff(\n baseFetchClient,\n backOffOpts\n )\n\n this.#sseFetchClient = fetchWithBackoffClient\n this.#fetchClient = createFetchWithConsumedBody(fetchWithBackoffClient)\n }\n\n // ============================================================================\n // Static convenience methods\n // ============================================================================\n\n /**\n * Create a new stream (create-only PUT) and return a handle.\n * Fails with DurableStreamError(code=\"CONFLICT_EXISTS\") if it already exists.\n */\n static async create(opts: CreateOptions): Promise<DurableStream> {\n const stream = new DurableStream(opts)\n await stream.create({\n contentType: opts.contentType,\n ttlSeconds: opts.ttlSeconds,\n expiresAt: opts.expiresAt,\n body: opts.body,\n })\n return stream\n }\n\n /**\n * Validate that a stream exists and fetch metadata via HEAD.\n * Returns a handle with contentType populated (if sent by server).\n */\n static async connect(opts: StreamOptions): Promise<DurableStream> {\n const stream = new DurableStream(opts)\n await stream.head()\n return stream\n }\n\n /**\n * HEAD metadata for a stream without creating a handle.\n */\n static async head(opts: StreamOptions): Promise<HeadResult> {\n const stream = new DurableStream(opts)\n return stream.head()\n }\n\n /**\n * Delete a stream without creating a handle.\n */\n static async delete(opts: StreamOptions): Promise<void> {\n const stream = new DurableStream(opts)\n return stream.delete()\n }\n\n // ============================================================================\n // Instance methods\n // ============================================================================\n\n /**\n * HEAD metadata for this stream.\n */\n async head(opts?: { signal?: AbortSignal }): Promise<HeadResult> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest()\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `HEAD`,\n headers: requestHeaders,\n signal: opts?.signal ?? this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new DurableStreamError(\n `Stream not found: ${this.url}`,\n `NOT_FOUND`,\n 404\n )\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n\n const contentType = response.headers.get(`content-type`) ?? undefined\n const offset = response.headers.get(STREAM_OFFSET_HEADER) ?? undefined\n const etag = response.headers.get(`etag`) ?? undefined\n const cacheControl = response.headers.get(`cache-control`) ?? undefined\n\n // Update instance contentType\n if (contentType) {\n this.contentType = contentType\n }\n\n return {\n exists: true,\n contentType,\n offset,\n etag,\n cacheControl,\n }\n }\n\n /**\n * Create this stream (create-only PUT) using the URL/auth from the handle.\n */\n async create(opts?: Omit<CreateOptions, keyof StreamOptions>): Promise<this> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest()\n\n if (opts?.contentType) {\n requestHeaders[`content-type`] = opts.contentType\n }\n if (opts?.ttlSeconds !== undefined) {\n requestHeaders[STREAM_TTL_HEADER] = String(opts.ttlSeconds)\n }\n if (opts?.expiresAt) {\n requestHeaders[STREAM_EXPIRES_AT_HEADER] = opts.expiresAt\n }\n\n const body = encodeBody(opts?.body)\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `PUT`,\n headers: requestHeaders,\n body,\n signal: this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 409) {\n throw new DurableStreamError(\n `Stream already exists: ${this.url}`,\n `CONFLICT_EXISTS`,\n 409\n )\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n\n // Update content type from response or options\n const responseContentType = response.headers.get(`content-type`)\n if (responseContentType) {\n this.contentType = responseContentType\n } else if (opts?.contentType) {\n this.contentType = opts.contentType\n }\n\n return this\n }\n\n /**\n * Delete this stream.\n */\n async delete(opts?: { signal?: AbortSignal }): Promise<void> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest()\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `DELETE`,\n headers: requestHeaders,\n signal: opts?.signal ?? this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new DurableStreamError(\n `Stream not found: ${this.url}`,\n `NOT_FOUND`,\n 404\n )\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n }\n\n /**\n * Append a single payload to the stream.\n *\n * - `body` may be Uint8Array, string, or any Fetch BodyInit.\n * - Strings are encoded as UTF-8.\n * - `seq` (if provided) is sent as stream-seq (writer coordination).\n */\n async append(\n body: BodyInit | Uint8Array | string,\n opts?: AppendOptions\n ): Promise<void> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest()\n\n if (opts?.contentType) {\n requestHeaders[`content-type`] = opts.contentType\n } else if (this.contentType) {\n requestHeaders[`content-type`] = this.contentType\n }\n\n if (opts?.seq) {\n requestHeaders[STREAM_SEQ_HEADER] = opts.seq\n }\n\n const encodedBody = encodeBody(body)\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `POST`,\n headers: requestHeaders,\n body: encodedBody,\n signal: opts?.signal ?? this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new DurableStreamError(\n `Stream not found: ${this.url}`,\n `NOT_FOUND`,\n 404\n )\n }\n if (response.status === 409) {\n throw new DurableStreamError(\n `Sequence conflict: seq is lower than last appended`,\n `CONFLICT_SEQ`,\n 409\n )\n }\n if (response.status === 400) {\n throw new DurableStreamError(\n `Bad request (possibly content-type mismatch)`,\n `BAD_REQUEST`,\n 400\n )\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n }\n\n /**\n * Append a streaming body to the stream.\n *\n * - `source` yields Uint8Array or string chunks.\n * - Strings are encoded as UTF-8; no delimiters are added.\n * - Internally uses chunked transfer or HTTP/2 streaming.\n */\n async appendStream(\n source:\n | ReadableStream<Uint8Array | string>\n | AsyncIterable<Uint8Array | string>,\n opts?: AppendOptions\n ): Promise<void> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest()\n\n if (opts?.contentType) {\n requestHeaders[`content-type`] = opts.contentType\n } else if (this.contentType) {\n requestHeaders[`content-type`] = this.contentType\n }\n\n if (opts?.seq) {\n requestHeaders[STREAM_SEQ_HEADER] = opts.seq\n }\n\n // Convert to ReadableStream if needed\n const body = toReadableStream(source)\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `POST`,\n headers: requestHeaders,\n body,\n // @ts-expect-error - duplex is needed for streaming but not in types\n duplex: `half`,\n signal: opts?.signal ?? this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new DurableStreamError(\n `Stream not found: ${this.url}`,\n `NOT_FOUND`,\n 404\n )\n }\n if (response.status === 409) {\n throw new DurableStreamError(\n `Sequence conflict: seq is lower than last appended`,\n `CONFLICT_SEQ`,\n 409\n )\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n }\n\n /**\n * One-shot read.\n *\n * Performs a single GET from the specified offset/mode and returns a chunk.\n * Caller is responsible for persisting the returned offset if they want to resume.\n */\n async read(opts?: ReadOptions): Promise<ReadResult> {\n const { requestHeaders, fetchUrl } = await this.#buildRequest(opts)\n\n const response = await this.#fetchClient(fetchUrl.toString(), {\n method: `GET`,\n headers: requestHeaders,\n signal: opts?.signal ?? this.#options.signal,\n })\n\n if (!response.ok) {\n if (response.status === 404) {\n throw new DurableStreamError(\n `Stream not found: ${this.url}`,\n `NOT_FOUND`,\n 404\n )\n }\n if (response.status === 204) {\n // Long-poll timeout - no new data\n const offset =\n response.headers.get(STREAM_OFFSET_HEADER) ?? opts?.offset ?? ``\n return {\n data: new Uint8Array(0),\n offset,\n upToDate: true,\n contentType: this.contentType,\n }\n }\n throw await DurableStreamError.fromResponse(response, this.url)\n }\n\n return this.#parseReadResponse(response)\n }\n\n /**\n * Follow the stream as an AsyncIterable of chunks.\n *\n * Default behaviour:\n * - From `offset` (or start if omitted), repeatedly perform catch-up reads\n * until a chunk with upToDate=true.\n * - Then switch to live mode:\n * - SSE if content-type is text/* or application/json;\n * - otherwise long-poll.\n *\n * Explicit live override:\n * - live=\"catchup\": only catch-up, stop at upToDate.\n * - live=\"long-poll\": start long-polling immediately from offset.\n * - live=\"sse\": start SSE immediately (throws if SSE not supported).\n */\n follow(opts?: ReadOptions): AsyncIterable<StreamChunk> {\n const stream = this\n const liveMode = opts?.live\n let currentOffset = opts?.offset\n let currentCursor = opts?.cursor\n let isUpToDate = false\n\n // Create a linked abort controller\n const aborter = new AbortController()\n const { signal, cleanup } = chainAborter(\n aborter,\n opts?.signal ?? stream.#options.signal\n )\n\n // SSE iterator - created once when we enter SSE mode\n let sseIterator: AsyncIterator<StreamChunk> | null = null\n\n return {\n [Symbol.asyncIterator](): AsyncIterator<StreamChunk> {\n return {\n async next(): Promise<IteratorResult<StreamChunk>> {\n try {\n // If we've been aborted, stop\n if (signal.aborted) {\n cleanup()\n return { done: true, value: undefined }\n }\n\n // If we have an SSE iterator, delegate to it\n if (sseIterator) {\n const result = await sseIterator.next()\n if (result.done) {\n // SSE connection closed - cleanup\n cleanup()\n }\n return result\n }\n\n // Determine which mode to use\n if (liveMode === `catchup`) {\n // Only do catch-up reads\n if (isUpToDate) {\n cleanup()\n return { done: true, value: undefined }\n }\n\n const chunk = await stream.read({\n offset: currentOffset,\n cursor: currentCursor,\n signal,\n })\n\n currentOffset = chunk.offset\n currentCursor = chunk.cursor\n isUpToDate = chunk.upToDate\n\n return { done: false, value: chunk }\n }\n\n if (liveMode === `sse`) {\n // SSE mode - create SSE iterator and delegate\n sseIterator = stream.#createSSEIterator(\n currentOffset,\n currentCursor,\n signal\n )\n return sseIterator.next()\n }\n\n if (liveMode === `long-poll`) {\n // Long-poll mode - skip catch-up\n const chunk = await stream.read({\n offset: currentOffset,\n cursor: currentCursor,\n live: `long-poll`,\n signal,\n })\n\n currentOffset = chunk.offset\n currentCursor = chunk.cursor\n\n return { done: false, value: chunk }\n }\n\n // Default mode: catch-up then auto-select live mode\n if (!isUpToDate) {\n // Catch-up phase\n const chunk = await stream.read({\n offset: currentOffset,\n cursor: currentCursor,\n signal,\n })\n\n currentOffset = chunk.offset\n currentCursor = chunk.cursor\n isUpToDate = chunk.upToDate\n\n // Update content type if not set\n if (chunk.contentType && !stream.contentType) {\n stream.contentType = chunk.contentType\n }\n\n return { done: false, value: chunk }\n }\n\n // Live phase - auto-select SSE or long-poll\n if (stream.#isSSECompatible()) {\n // Create SSE iterator and delegate\n sseIterator = stream.#createSSEIterator(\n currentOffset,\n currentCursor,\n signal\n )\n return sseIterator.next()\n } else {\n // Long-poll\n const chunk = await stream.read({\n offset: currentOffset,\n cursor: currentCursor,\n live: `long-poll`,\n signal,\n })\n\n currentOffset = chunk.offset\n currentCursor = chunk.cursor\n\n return { done: false, value: chunk }\n }\n } catch (e) {\n if (e instanceof FetchBackoffAbortError) {\n cleanup()\n return { done: true, value: undefined }\n }\n\n // Handle error with onError callback (following Electric's pattern)\n if (stream.#onError && e instanceof Error) {\n const retryOpts = await stream.#onError(e)\n // Guard against null (typeof null === \"object\" in JavaScript)\n if (retryOpts && typeof retryOpts === `object`) {\n // Update params/headers but don't reset offset\n // We want to continue from where we left off, not refetch everything\n if (retryOpts.params) {\n // Merge new params with existing params to preserve other parameters\n stream.#options.params = {\n ...(stream.#options.params ?? {}),\n ...retryOpts.params,\n }\n }\n\n if (retryOpts.headers) {\n // Merge new headers with existing headers to preserve other headers\n stream.#options.headers = {\n ...(stream.#options.headers ?? {}),\n ...retryOpts.headers,\n }\n }\n\n // Retry without cleanup - keep abort listener chain intact\n return this.next()\n }\n }\n\n // Only cleanup when we're actually terminating\n cleanup()\n throw e\n }\n },\n\n async return(): Promise<IteratorResult<StreamChunk>> {\n // Clean up SSE iterator if it exists\n if (sseIterator?.return) {\n await sseIterator.return()\n }\n cleanup()\n aborter.abort()\n return { done: true, value: undefined }\n },\n }\n },\n }\n }\n\n /**\n * Wrap follow() in a Web ReadableStream for piping.\n *\n * Backpressure:\n * - One chunk is pulled from follow() per pull() call, so standard\n * Web Streams backpressure semantics apply.\n *\n * Cancellation:\n * - rs.cancel() will stop follow() and abort any in-flight request.\n */\n toReadableStream(\n opts?: ReadOptions & { signal?: AbortSignal }\n ): ReadableStream<StreamChunk> {\n const iterator = this.follow(opts)[Symbol.asyncIterator]()\n\n return new ReadableStream<StreamChunk>({\n async pull(controller) {\n try {\n const { done, value } = await iterator.next()\n if (done) {\n controller.close()\n } else {\n controller.enqueue(value)\n }\n } catch (e) {\n controller.error(e)\n }\n },\n\n cancel() {\n iterator.return?.()\n },\n })\n }\n\n /**\n * Wrap follow() in a Web ReadableStream<Uint8Array> for piping raw bytes.\n *\n * This is the native format for many web stream APIs.\n */\n toByteStream(\n opts?: ReadOptions & { signal?: AbortSignal }\n ): ReadableStream<Uint8Array> {\n const iterator = this.follow(opts)[Symbol.asyncIterator]()\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await iterator.next()\n if (done) {\n controller.close()\n } else {\n controller.enqueue(value.data)\n }\n } catch (e) {\n controller.error(e)\n }\n },\n\n cancel() {\n iterator.return?.()\n },\n })\n }\n\n /**\n * Convenience: interpret data as JSON messages.\n * Parses each chunk's data as JSON and yields the parsed values.\n */\n async *json<T = unknown>(opts?: ReadOptions): AsyncIterable<T> {\n const decoder = new TextDecoder()\n\n for await (const chunk of this.follow(opts)) {\n if (chunk.data.length > 0) {\n const text = decoder.decode(chunk.data)\n // Handle potential newline-delimited JSON\n const lines = text.split(`\\n`).filter((l) => l.trim())\n for (const line of lines) {\n yield JSON.parse(line) as T\n }\n }\n }\n }\n\n /**\n * Convenience: interpret data as text (UTF-8).\n */\n async *text(\n opts?: ReadOptions & { decoder?: TextDecoder }\n ): AsyncIterable<string> {\n const decoder = opts?.decoder ?? new TextDecoder()\n\n for await (const chunk of this.follow(opts)) {\n if (chunk.data.length > 0) {\n yield decoder.decode(chunk.data, { stream: true })\n }\n }\n }\n\n // ============================================================================\n // Private methods\n // ============================================================================\n\n /**\n * Build request headers and URL.\n */\n async #buildRequest(\n readOpts?: ReadOptions\n ): Promise<{ requestHeaders: Record<string, string>; fetchUrl: URL }> {\n const requestHeaders = await this.#resolveHeaders()\n const fetchUrl = new URL(this.url)\n\n // Add params\n const params = this.#options.params\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n const resolved = await resolveValue(value)\n fetchUrl.searchParams.set(key, resolved)\n }\n }\n }\n\n // Add read options to URL\n if (readOpts) {\n if (readOpts.offset) {\n fetchUrl.searchParams.set(OFFSET_QUERY_PARAM, readOpts.offset)\n }\n if (readOpts.live) {\n fetchUrl.searchParams.set(LIVE_QUERY_PARAM, readOpts.live)\n }\n if (readOpts.cursor) {\n fetchUrl.searchParams.set(CURSOR_QUERY_PARAM, readOpts.cursor)\n }\n }\n\n return { requestHeaders, fetchUrl }\n }\n\n /**\n * Resolve headers from auth and headers options.\n */\n async #resolveHeaders(): Promise<Record<string, string>> {\n const headers: Record<string, string> = {}\n\n // Resolve auth\n const auth = this.#options.auth\n if (auth) {\n if (`token` in auth) {\n const headerName = auth.headerName ?? `authorization`\n headers[headerName] = `Bearer ${auth.token}`\n } else if (`headers` in auth) {\n Object.assign(headers, auth.headers)\n } else if (`getHeaders` in auth) {\n const authHeaders = await auth.getHeaders()\n Object.assign(headers, authHeaders)\n }\n }\n\n // Resolve additional headers\n const headersOpt = this.#options.headers\n if (headersOpt) {\n for (const [key, value] of Object.entries(headersOpt)) {\n headers[key] = await resolveValue(value)\n }\n }\n\n return headers\n }\n\n /**\n * Parse a read response into a ReadResult.\n */\n async #parseReadResponse(response: Response): Promise<ReadResult> {\n const data = new Uint8Array(await response.arrayBuffer())\n const offset = response.headers.get(STREAM_OFFSET_HEADER) ?? ``\n const cursor = response.headers.get(STREAM_CURSOR_HEADER) ?? undefined\n const upToDate = response.headers.has(STREAM_UP_TO_DATE_HEADER)\n const etag = response.headers.get(`etag`) ?? undefined\n const contentType = response.headers.get(`content-type`) ?? undefined\n\n // Update instance contentType\n if (contentType && !this.contentType) {\n this.contentType = contentType\n }\n\n return {\n data,\n offset,\n cursor,\n upToDate,\n etag,\n contentType,\n }\n }\n\n /**\n * Check if the stream's content type is compatible with SSE.\n */\n #isSSECompatible(): boolean {\n if (!this.contentType) return false\n\n return SSE_COMPATIBLE_CONTENT_TYPES.some((prefix) =>\n this.contentType!.startsWith(prefix)\n )\n }\n\n /**\n * Create an SSE connection that maintains a persistent connection with an internal queue.\n * Returns an AsyncIterator that yields chunks as they arrive.\n *\n * Follows the Electric client pattern:\n * - Buffer data events until control event (up-to-date)\n * - Flush buffer on control event\n * - Use promise chain for sequential processing\n */\n #createSSEIterator(\n initialOffset: Offset | undefined,\n initialCursor: string | undefined,\n signal: AbortSignal\n ): AsyncIterator<StreamChunk> {\n // Check SSE compatibility\n if (!this.#isSSECompatible()) {\n throw new DurableStreamError(\n `SSE is not supported for content-type: ${this.contentType}`,\n `SSE_NOT_SUPPORTED`,\n 400\n )\n }\n\n // Queue of complete chunks waiting to be consumed\n const chunkQueue: Array<StreamChunk> = []\n\n // Pending resolve for when next() is waiting for data\n let pendingResolve: ((result: IteratorResult<StreamChunk>) => void) | null =\n null\n\n // Track current offset/cursor\n let currentOffset = initialOffset\n let currentCursor = initialCursor\n\n // Connection state\n let connectionClosed = false\n let connectionError: Error | null = null\n\n // Abort controller to close the connection\n const connectionAbort = new AbortController()\n\n // Buffer for accumulating data events before control event\n let dataBuffer: Array<Uint8Array> = []\n\n const stream = this\n\n // Start the SSE connection (following Electric's pattern)\n const startConnection = async (): Promise<void> => {\n const { requestHeaders, fetchUrl } = await stream.#buildRequest({\n offset: currentOffset,\n cursor: currentCursor,\n live: `sse`,\n })\n\n try {\n await fetchEventSource(fetchUrl.toString(), {\n headers: requestHeaders,\n fetch: stream.#sseFetchClient,\n signal: signal.aborted ? signal : connectionAbort.signal,\n\n onopen: async (response: Response) => {\n if (!response.ok) {\n throw await DurableStreamError.fromResponse(response, stream.url)\n }\n\n // Update content type\n const contentType = response.headers.get(`content-type`)\n if (contentType && !stream.contentType) {\n stream.contentType = contentType\n }\n },\n\n onmessage: (event: EventSourceMessage) => {\n if (event.event === `data` && event.data) {\n // Data event - buffer the data (following Electric's buffer pattern)\n const data = stream.#parseSSEData(event.data)\n dataBuffer.push(data)\n } else if (event.event === `control` && event.data) {\n // Control event - flush the buffer (like Electric's up-to-date message)\n try {\n const control = JSON.parse(event.data) as {\n [STREAM_OFFSET_HEADER]?: string\n [STREAM_CURSOR_HEADER]?: string\n }\n\n const newOffset = control[STREAM_OFFSET_HEADER]\n const newCursor = control[STREAM_CURSOR_HEADER]\n\n // Concatenate buffered data\n const totalSize = dataBuffer.reduce(\n (sum, buf) => sum + buf.length,\n 0\n )\n const combinedData = new Uint8Array(totalSize)\n let offset = 0\n for (const buf of dataBuffer) {\n combinedData.set(buf, offset)\n offset += buf.length\n }\n\n // Create complete chunk\n const chunk: StreamChunk = {\n data: combinedData,\n offset: newOffset ?? currentOffset ?? ``,\n cursor: newCursor,\n upToDate: true,\n contentType: stream.contentType,\n }\n\n // Update state\n currentOffset = chunk.offset\n currentCursor = chunk.cursor\n\n // Clear buffer\n dataBuffer = []\n\n // If someone is waiting for data, resolve immediately\n if (pendingResolve) {\n const resolve = pendingResolve\n pendingResolve = null\n resolve({ done: false, value: chunk })\n } else {\n // Otherwise queue it\n chunkQueue.push(chunk)\n }\n } catch {\n // Ignore malformed control messages\n }\n }\n },\n\n onerror: (error: Error) => {\n // Rethrow to close SSE connection (following Electric's pattern)\n throw error\n },\n })\n } catch (error) {\n // Handle abort during SSE parsing (following Electric's pattern)\n if (connectionAbort.signal.aborted || signal.aborted) {\n throw new FetchBackoffAbortError()\n }\n throw error\n }\n }\n\n // Start the connection (don't await - runs in background)\n const connectionPromise = startConnection().catch((e) => {\n if (e instanceof FetchBackoffAbortError) {\n connectionClosed = true\n } else {\n connectionError = e\n connectionClosed = true\n }\n\n // If someone is waiting, signal done or error\n if (pendingResolve) {\n const resolve = pendingResolve\n pendingResolve = null\n resolve({ done: true, value: undefined })\n }\n })\n\n // Also close on external abort\n const abortHandler = (): void => {\n connectionAbort.abort()\n connectionClosed = true\n if (pendingResolve) {\n const resolve = pendingResolve\n pendingResolve = null\n resolve({ done: true, value: undefined })\n }\n }\n signal.addEventListener(`abort`, abortHandler, { once: true })\n\n return {\n async next(): Promise<IteratorResult<StreamChunk>> {\n // If there's queued data, return it immediately\n if (chunkQueue.length > 0) {\n return { done: false, value: chunkQueue.shift()! }\n }\n\n // If connection errored, throw the error\n if (connectionError) {\n throw connectionError\n }\n\n // If connection closed (e.g., aborted), we're done\n if (connectionClosed || signal.aborted) {\n return { done: true, value: undefined }\n }\n\n // Wait for the next chunk\n return new Promise((resolve) => {\n pendingResolve = resolve\n })\n },\n\n async return(): Promise<IteratorResult<StreamChunk>> {\n signal.removeEventListener(`abort`, abortHandler)\n connectionAbort.abort()\n connectionClosed = true\n\n // Wait for connection cleanup\n await connectionPromise.catch(() => {\n // Ignore errors during cleanup\n })\n\n return { done: true, value: undefined }\n },\n }\n }\n\n /**\n * Parse SSE data payload.\n * For application/json, data is wrapped in [ and ], so we unwrap it.\n */\n #parseSSEData(data: string): Uint8Array {\n // SSE data lines are prefixed with \"data: \" and may be wrapped in [ ]\n // for application/json content\n const lines = data.split(`\\n`)\n const content = lines\n .map((line) => {\n // Remove \"data: \" prefix if present\n if (line.startsWith(`data: `)) {\n return line.slice(6)\n }\n return line\n })\n .join(`\\n`)\n\n // For JSON content, unwrap the array wrapper\n let text = content.trim()\n if (\n this.contentType?.includes(`application/json`) &&\n text.startsWith(`[`) &&\n text.endsWith(`]`)\n ) {\n // Remove the wrapper brackets and trailing comma if present\n text = text.slice(1, -1).trim()\n if (text.endsWith(`,`)) {\n text = text.slice(0, -1)\n }\n }\n\n return new TextEncoder().encode(text)\n }\n}\n\n// ============================================================================\n// Utility functions\n// ============================================================================\n\n/**\n * Resolve a value that may be a function.\n */\nasync function resolveValue<T>(value: T | (() => MaybePromise<T>)): Promise<T> {\n if (typeof value === `function`) {\n return (value as () => MaybePromise<T>)()\n }\n return value\n}\n\n/**\n * Encode a body value to the appropriate format.\n * Strings are encoded as UTF-8.\n */\nfunction encodeBody(\n body: BodyInit | Uint8Array | string | undefined\n): BodyInit | undefined {\n if (body === undefined) {\n return undefined\n }\n if (typeof body === `string`) {\n return new TextEncoder().encode(body)\n }\n if (body instanceof Uint8Array) {\n // Cast to ensure compatible BodyInit type\n return body as unknown as BodyInit\n }\n return body\n}\n\n/**\n * Convert an async iterable to a ReadableStream.\n */\nfunction toReadableStream(\n source:\n | ReadableStream<Uint8Array | string>\n | AsyncIterable<Uint8Array | string>\n): ReadableStream<Uint8Array> {\n // If it's already a ReadableStream, transform it\n if (source instanceof ReadableStream) {\n return source.pipeThrough(\n new TransformStream<Uint8Array | string, Uint8Array>({\n transform(chunk, controller) {\n if (typeof chunk === `string`) {\n controller.enqueue(new TextEncoder().encode(chunk))\n } else {\n controller.enqueue(chunk)\n }\n },\n })\n )\n }\n\n // Convert async iterable to ReadableStream\n const encoder = new TextEncoder()\n const iterator = source[Symbol.asyncIterator]()\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const { done, value } = await iterator.next()\n if (done) {\n controller.close()\n } else if (typeof value === `string`) {\n controller.enqueue(encoder.encode(value))\n } else {\n controller.enqueue(value)\n }\n } catch (e) {\n controller.error(e)\n }\n },\n\n cancel() {\n iterator.return?.()\n },\n })\n}\n\n/**\n * Validate stream options.\n */\nfunction validateOptions(options: Partial<DurableStreamOptions>): void {\n if (!options.url) {\n throw new MissingStreamUrlError()\n }\n if (options.signal && !(options.signal instanceof AbortSignal)) {\n throw new InvalidSignalError()\n }\n}\n","import type { DurableStreamErrorCode } from \"./types\"\n\n/**\n * Error thrown for transport/network errors.\n * Following the @electric-sql/client FetchError pattern.\n */\nexport class FetchError extends Error {\n status: number\n text?: string\n json?: object\n headers: Record<string, string>\n\n constructor(\n status: number,\n text: string | undefined,\n json: object | undefined,\n headers: Record<string, string>,\n public url: string,\n message?: string\n ) {\n super(\n message ||\n `HTTP Error ${status} at ${url}: ${text ?? JSON.stringify(json)}`\n )\n this.name = `FetchError`\n this.status = status\n this.text = text\n this.json = json\n this.headers = headers\n }\n\n static async fromResponse(\n response: Response,\n url: string\n ): Promise<FetchError> {\n const status = response.status\n const headers = Object.fromEntries([...response.headers.entries()])\n let text: string | undefined = undefined\n let json: object | undefined = undefined\n\n const contentType = response.headers.get(`content-type`)\n if (!response.bodyUsed) {\n if (contentType && contentType.includes(`application/json`)) {\n try {\n json = (await response.json()) as object\n } catch {\n // If JSON parsing fails, fall back to text\n text = await response.text()\n }\n } else {\n text = await response.text()\n }\n }\n\n return new FetchError(status, text, json, headers, url)\n }\n}\n\n/**\n * Error thrown when a fetch operation is aborted during backoff.\n */\nexport class FetchBackoffAbortError extends Error {\n constructor() {\n super(`Fetch with backoff aborted`)\n this.name = `FetchBackoffAbortError`\n }\n}\n\n/**\n * Protocol-level error for Durable Streams operations.\n * Provides structured error handling with error codes.\n */\nexport class DurableStreamError extends Error {\n /**\n * HTTP status code, if applicable.\n */\n status?: number\n\n /**\n * Structured error code for programmatic handling.\n */\n code: DurableStreamErrorCode\n\n /**\n * Additional error details (e.g., raw response body).\n */\n details?: unknown\n\n constructor(\n message: string,\n code: DurableStreamErrorCode,\n status?: number,\n details?: unknown\n ) {\n super(message)\n this.name = `DurableStreamError`\n this.code = code\n this.status = status\n this.details = details\n }\n\n /**\n * Create a DurableStreamError from an HTTP response.\n */\n static async fromResponse(\n response: Response,\n url: string\n ): Promise<DurableStreamError> {\n const status = response.status\n let details: unknown\n\n const contentType = response.headers.get(`content-type`)\n if (!response.bodyUsed) {\n if (contentType && contentType.includes(`application/json`)) {\n try {\n details = await response.json()\n } catch {\n details = await response.text()\n }\n } else {\n details = await response.text()\n }\n }\n\n const code = statusToCode(status)\n const message = `Durable stream error at ${url}: ${response.statusText || status}`\n\n return new DurableStreamError(message, code, status, details)\n }\n\n /**\n * Create a DurableStreamError from a FetchError.\n */\n static fromFetchError(error: FetchError): DurableStreamError {\n const code = statusToCode(error.status)\n return new DurableStreamError(\n error.message,\n code,\n error.status,\n error.json ?? error.text\n )\n }\n}\n\n/**\n * Map HTTP status codes to DurableStreamErrorCode.\n */\nfunction statusToCode(status: number): DurableStreamErrorCode {\n switch (status) {\n case 400:\n return `BAD_REQUEST`\n case 401:\n return `UNAUTHORIZED`\n case 403:\n return `FORBIDDEN`\n case 404:\n return `NOT_FOUND`\n case 409:\n // Could be CONFLICT_SEQ or CONFLICT_EXISTS depending on context\n // Default to CONFLICT_SEQ, caller can override\n return `CONFLICT_SEQ`\n case 429:\n return `RATE_LIMITED`\n case 503:\n return `BUSY`\n default:\n return `UNKNOWN`\n }\n}\n\n/**\n * Error thrown when stream URL is missing.\n */\nexport class MissingStreamUrlError extends Error {\n constructor() {\n super(`Invalid stream options: missing required url parameter`)\n this.name = `MissingStreamUrlError`\n }\n}\n\n/**\n * Error thrown when signal option is invalid.\n */\nexport class InvalidSignalError extends Error {\n constructor() {\n super(`Invalid signal option. It must be an instance of AbortSignal.`)\n this.name = `InvalidSignalError`\n }\n}\n","/**\n * Durable Streams Protocol Constants\n *\n * Header and query parameter names following the Electric Durable Stream Protocol.\n */\n\n// ============================================================================\n// Response Headers\n// ============================================================================\n\n/**\n * Response header containing the next offset to read from.\n * Format: \"<read-seq>_<byte-offset>\"\n */\nexport const STREAM_OFFSET_HEADER = `stream-offset`\n\n/**\n * Response header for cursor (used for CDN collapsing).\n * Echo this value in subsequent long-poll requests.\n */\nexport const STREAM_CURSOR_HEADER = `stream-cursor`\n\n/**\n * Presence header indicating response ends at current end of stream.\n * When present (any value), indicates up-to-date.\n */\nexport const STREAM_UP_TO_DATE_HEADER = `stream-up-to-date`\n\n// ============================================================================\n// Request Headers\n// ============================================================================\n\n/**\n * Request header for writer coordination sequence.\n * Monotonic, lexicographic. If lower than last appended seq -> 409 Conflict.\n */\nexport const STREAM_SEQ_HEADER = `stream-seq`\n\n/**\n * Request header for stream TTL in seconds (on create).\n */\nexport const STREAM_TTL_HEADER = `stream-ttl`\n\n/**\n * Request header for absolute stream expiry time (RFC3339, on create).\n */\nexport const STREAM_EXPIRES_AT_HEADER = `stream-expires-at`\n\n// ============================================================================\n// Query Parameters\n// ============================================================================\n\n/**\n * Query parameter for starting offset.\n */\nexport const OFFSET_QUERY_PARAM = `offset`\n\n/**\n * Query parameter for live mode.\n * Values: \"long-poll\", \"sse\"\n */\nexport const LIVE_QUERY_PARAM = `live`\n\n/**\n * Query parameter for echoing cursor (CDN collapsing).\n */\nexport const CURSOR_QUERY_PARAM = `cursor`\n\n// ============================================================================\n// Internal Constants\n// ============================================================================\n\n/**\n * Content types that support SSE mode.\n * SSE is only valid for text/* or application/json streams.\n */\nexport const SSE_COMPATIBLE_CONTENT_TYPES = [`text/`, `application/json`]\n\n/**\n * Protocol query parameters that should not be set by users.\n */\nexport const DURABLE_STREAM_PROTOCOL_QUERY_PARAMS: Array<string> = [\n OFFSET_QUERY_PARAM,\n LIVE_QUERY_PARAM,\n CURSOR_QUERY_PARAM,\n]\n","/**\n * Fetch utilities with retry and backoff support.\n * Based on @electric-sql/client patterns.\n */\n\nimport { FetchBackoffAbortError, FetchError } from \"./error\"\n\n/**\n * HTTP status codes that should be retried.\n */\nconst HTTP_RETRY_STATUS_CODES = [429, 503]\n\n/**\n * Options for configuring exponential backoff retry behavior.\n */\nexport interface BackoffOptions {\n /**\n * Initial delay before retrying in milliseconds.\n */\n initialDelay: number\n\n /**\n * Maximum retry delay in milliseconds.\n * After reaching this, delay stays constant.\n */\n maxDelay: number\n\n /**\n * Multiplier for exponential backoff.\n */\n multiplier: number\n\n /**\n * Callback invoked on each failed attempt.\n */\n onFailedAttempt?: () => void\n\n /**\n * Enable debug logging.\n */\n debug?: boolean\n\n /**\n * Maximum number of retry attempts before giving up.\n * Set to Infinity for indefinite retries (useful for offline scenarios).\n */\n maxRetries?: number\n}\n\n/**\n * Default backoff options.\n */\nexport const BackoffDefaults: BackoffOptions = {\n initialDelay: 100,\n maxDelay: 60_000, // Cap at 60s\n multiplier: 1.3,\n maxRetries: Infinity, // Retry forever by default\n}\n\n/**\n * Parse Retry-After header value and return delay in milliseconds.\n * Supports both delta-seconds format and HTTP-date format.\n * Returns 0 if header is not present or invalid.\n */\nexport function parseRetryAfterHeader(retryAfter: string | undefined): number {\n if (!retryAfter) return 0\n\n // Try parsing as seconds (delta-seconds format)\n const retryAfterSec = Number(retryAfter)\n if (Number.isFinite(retryAfterSec) && retryAfterSec > 0) {\n return retryAfterSec * 1000\n }\n\n // Try parsing as HTTP-date\n const retryDate = Date.parse(retryAfter)\n if (!isNaN(retryDate)) {\n // Handle clock skew: clamp to non-negative, cap at reasonable max\n const deltaMs = retryDate - Date.now()\n return Math.max(0, Math.min(deltaMs, 3600_000)) // Cap at 1 hour\n }\n\n return 0\n}\n\n/**\n * Creates a fetch client that retries failed requests with exponential backoff.\n *\n * @param fetchClient - The base fetch client to wrap\n * @param backoffOptions - Options for retry behavior\n * @returns A fetch function with automatic retry\n */\nexport function createFetchWithBackoff(\n fetchClient: typeof fetch,\n backoffOptions: BackoffOptions = BackoffDefaults\n): typeof fetch {\n const {\n initialDelay,\n maxDelay,\n multiplier,\n debug = false,\n onFailedAttempt,\n maxRetries = Infinity,\n } = backoffOptions\n\n return async (...args: Parameters<typeof fetch>): Promise<Response> => {\n const url = args[0]\n const options = args[1]\n\n let delay = initialDelay\n let attempt = 0\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n while (true) {\n try {\n const result = await fetchClient(...args)\n if (result.ok) {\n return result\n }\n\n const err = await FetchError.fromResponse(result, url.toString())\n throw err\n } catch (e) {\n onFailedAttempt?.()\n\n if (options?.signal?.aborted) {\n throw new FetchBackoffAbortError()\n } else if (\n e instanceof FetchError &&\n !HTTP_RETRY_STATUS_CODES.includes(e.status) &&\n e.status >= 400 &&\n e.status < 500\n ) {\n // Client errors (except 429) cannot be backed off on\n throw e\n } else {\n // Check max retries\n attempt++\n if (attempt > maxRetries) {\n if (debug) {\n console.log(\n `Max retries reached (${attempt}/${maxRetries}), giving up`\n )\n }\n throw e\n }\n\n // Calculate wait time honoring server-driven backoff as a floor\n // Parse server-provided Retry-After (if present)\n const serverMinimumMs =\n e instanceof FetchError\n ? parseRetryAfterHeader(e.headers[`retry-after`])\n : 0\n\n // Calculate client backoff with full jitter strategy\n // Full jitter: random_between(0, min(cap, exponential_backoff))\n const jitter = Math.random() * delay\n const clientBackoffMs = Math.min(jitter, maxDelay)\n\n // Server minimum is the floor, client cap is the ceiling\n const waitMs = Math.max(serverMinimumMs, clientBackoffMs)\n\n if (debug) {\n const source = serverMinimumMs > 0 ? `server+client` : `client`\n console.log(\n `Retry attempt #${attempt} after ${waitMs}ms (${source}, serverMin=${serverMinimumMs}ms, clientBackoff=${clientBackoffMs}ms)`\n )\n }\n\n // Wait for the calculated duration\n await new Promise((resolve) => setTimeout(resolve, waitMs))\n\n // Increase the delay for the next attempt (capped at maxDelay)\n delay = Math.min(delay * multiplier, maxDelay)\n }\n }\n }\n }\n}\n\n/**\n * Status codes where we shouldn't try to read the body.\n */\nconst NO_BODY_STATUS_CODES = [201, 204, 205]\n\n/**\n * Creates a fetch client that ensures the response body is fully consumed.\n * This prevents issues with connection pooling when bodies aren't read.\n *\n * Uses arrayBuffer() instead of text() to preserve binary data integrity.\n *\n * @param fetchClient - The base fetch client to wrap\n * @returns A fetch function that consumes response bodies\n */\nexport function createFetchWithConsumedBody(\n fetchClient: typeof fetch\n): typeof fetch {\n return async (...args: Parameters<typeof fetch>): Promise<Response> => {\n const url = args[0]\n const res = await fetchClient(...args)\n\n try {\n if (res.status < 200 || NO_BODY_STATUS_CODES.includes(res.status)) {\n return res\n }\n\n // Read body as arrayBuffer to preserve binary data integrity\n const buf = await res.arrayBuffer()\n return new Response(buf, {\n status: res.status,\n statusText: res.statusText,\n headers: res.headers,\n })\n } catch (err) {\n if (args[1]?.signal?.aborted) {\n throw new FetchBackoffAbortError()\n }\n\n throw new FetchError(\n res.status,\n undefined,\n undefined,\n Object.fromEntries([...res.headers.entries()]),\n url.toString(),\n err instanceof Error\n ? err.message\n : typeof err === `string`\n ? err\n : `failed to read body`\n )\n }\n }\n}\n\n/**\n * Chains an AbortController to an optional source signal.\n * If the source signal is aborted, the provided controller will also abort.\n */\nexport function chainAborter(\n aborter: AbortController,\n sourceSignal?: AbortSignal | null\n): {\n signal: AbortSignal\n cleanup: () => void\n} {\n let cleanup = noop\n if (!sourceSignal) {\n // no-op, nothing to chain to\n } else if (sourceSignal.aborted) {\n // source signal is already aborted, abort immediately\n aborter.abort(sourceSignal.reason)\n } else {\n // chain to source signal abort event\n const abortParent = () => aborter.abort(sourceSignal.reason)\n sourceSignal.addEventListener(`abort`, abortParent, {\n once: true,\n signal: aborter.signal,\n })\n cleanup = () => sourceSignal.removeEventListener(`abort`, abortParent)\n }\n\n return {\n signal: aborter.signal,\n cleanup,\n }\n}\n\nfunction noop() {}\n"],"mappings":"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","names":["_a"]}
|