@runlane/realtime 0.5.0 → 0.5.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/dist/client.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_time = require("./time-BhORZuav.cjs");
2
+ const require_wire = require("./wire-xCr4QuVn.cjs");
3
3
  let _runlane_contracts_realtime = require("@runlane/contracts/realtime");
4
4
  let _runlane_utilities_browser = require("@runlane/utilities/browser");
5
5
  let zod = require("zod");
6
- zod = require_time.__toESM(zod, 1);
6
+ zod = require_wire.__toESM(zod, 1);
7
7
  let eventsource_parser = require("eventsource-parser");
8
8
  // src/connection-observer.ts
9
9
  /** Owns notification ordering and preserves the first callback failure without recursive reporting. */
@@ -53,7 +53,7 @@ var ConnectionObserver = class {
53
53
  }
54
54
  };
55
55
  // src/sse.ts
56
- const encoder$1 = new TextEncoder();
56
+ const encoder = new TextEncoder();
57
57
  /** Incremental UTF-8 SSE parser; incomplete trailing events are never dispatched. */
58
58
  async function* readSse(body, signal) {
59
59
  const reader = body.getReader();
@@ -74,7 +74,7 @@ async function* readSse(body, signal) {
74
74
  };
75
75
  },
76
76
  onError(error) {
77
- if (error.type === "max-buffer-size-exceeded") throw require_time.wireInvalid(error);
77
+ if (error.type === "max-buffer-size-exceeded") throw require_wire.wireInvalid(error);
78
78
  }
79
79
  });
80
80
  const abort = () => {
@@ -116,8 +116,8 @@ var FrameByteBudget = class {
116
116
  this.resetAfterCr = false;
117
117
  }
118
118
  const point = char.codePointAt(0) ?? 0;
119
- this.retained += point < 128 ? 1 : encoder$1.encode(char).byteLength;
120
- if (this.retained > _runlane_contracts_realtime.realtimeDefaults.maxEventBytes) throw require_time.wireInvalid();
119
+ this.retained += point < 128 ? 1 : encoder.encode(char).byteLength;
120
+ if (this.retained > _runlane_contracts_realtime.realtimeDefaults.maxEventBytes) throw require_wire.wireInvalid();
121
121
  if (this.skipLf && char === "\n") {
122
122
  this.skipLf = false;
123
123
  if (this.resetAfterCr) {
@@ -152,18 +152,7 @@ function decodeUtf8(decoder, bytes) {
152
152
  try {
153
153
  return bytes === void 0 ? decoder.decode() : decoder.decode(bytes, { stream: true });
154
154
  } catch (cause) {
155
- throw require_time.wireInvalid(cause);
156
- }
157
- }
158
- // src/wire.ts
159
- const encoder = new TextEncoder();
160
- /** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */
161
- function parseWireJson(text) {
162
- try {
163
- if (encoder.encode(text).byteLength > _runlane_contracts_realtime.realtimeDefaults.maxEventBytes) throw require_time.wireInvalid();
164
- return JSON.parse(text);
165
- } catch (cause) {
166
- throw require_time.wireInvalid(cause);
155
+ throw require_wire.wireInvalid(cause);
167
156
  }
168
157
  }
169
158
  // src/client.ts
@@ -182,7 +171,8 @@ const readerFields = {
182
171
  const readerRequestSchema = zod.discriminatedUnion("kind", [zod.object({
183
172
  ...readerFields,
184
173
  kind: zod.literal(_runlane_contracts_realtime.RunReaderKind.Subscription),
185
- name: zod.undefined()
174
+ name: zod.undefined(),
175
+ streams: zod.literal(false).optional()
186
176
  }), zod.object({
187
177
  ...readerFields,
188
178
  kind: zod.literal(_runlane_contracts_realtime.RunReaderKind.Stream),
@@ -191,7 +181,7 @@ const readerRequestSchema = zod.discriminatedUnion("kind", [zod.object({
191
181
  /** Creates a reusable authenticated streaming client with bounded parsing and reconnect delays. */
192
182
  function createRunlaneClient(options) {
193
183
  const checked = clientOptionsSchema.safeParse(options);
194
- if (!checked.success) throw require_time.invalidOptions(checked.error, "client");
184
+ if (!checked.success) throw require_wire.invalidOptions(checked.error, "client");
195
185
  const base = checked.data.baseUrl;
196
186
  const fetcher = options.fetch ?? globalThis.fetch;
197
187
  async function* subscribe(runId, input) {
@@ -210,15 +200,17 @@ async function* connect(options, fetcher, base, runId, name, kind, input = {}) {
210
200
  kind,
211
201
  runId,
212
202
  name,
213
- after: input.after
203
+ after: input.after,
204
+ streams: input.streams
214
205
  });
215
206
  if (!checked.success) throw new _runlane_contracts_realtime.RunlaneError({
216
207
  code: checked.error.issues[0]?.path[0] === "after" ? _runlane_contracts_realtime.ErrorCode.RunCursorInvalid : _runlane_contracts_realtime.ErrorCode.ValidationFailed,
217
- message: "Run id, stream name, or after cursor is invalid.",
208
+ message: "Run id, stream name, stream selection, or after cursor is invalid.",
218
209
  cause: checked.error
219
210
  });
220
211
  const request = checked.data;
221
212
  const url = makeUrl(base, request.runId, request.name);
213
+ if (request.kind === _runlane_contracts_realtime.RunReaderKind.Subscription && request.streams === false) url.searchParams.set(require_wire.streamSelectionQuery.name, require_wire.streamSelectionQuery.none);
222
214
  const signal = input.signal ?? new AbortController().signal;
223
215
  const observer = new ConnectionObserver(input.onConnectionChange);
224
216
  let failure;
@@ -262,7 +254,7 @@ var ReconnectState = class {
262
254
  refreshAccessToken;
263
255
  cursor;
264
256
  records = /* @__PURE__ */ new Set();
265
- delay = require_time.realtimeTiming.clientReconnectDelay;
257
+ delay = require_wire.realtimeTiming.clientReconnectDelay;
266
258
  attempts = 0;
267
259
  failures = 0;
268
260
  openedAt;
@@ -309,8 +301,8 @@ var ReconnectState = class {
309
301
  open() {
310
302
  this.refreshedAfterDenial = false;
311
303
  this.attempts = 0;
312
- this.delay = require_time.realtimeTiming.clientReconnectDelay;
313
- this.openedAt = require_time.realtimeClock.now();
304
+ this.delay = require_wire.realtimeTiming.clientReconnectDelay;
305
+ this.openedAt = require_wire.realtimeClock.now();
314
306
  }
315
307
  deliverRecord(id) {
316
308
  if (this.records.has(id)) return false;
@@ -324,11 +316,11 @@ var ReconnectState = class {
324
316
  this.failures = 0;
325
317
  this.lastFailure = void 0;
326
318
  this.attempts = 0;
327
- this.delay = require_time.realtimeTiming.clientReconnectDelay;
319
+ this.delay = require_wire.realtimeTiming.clientReconnectDelay;
328
320
  }
329
321
  schedule(signal, observer) {
330
322
  if (signal.aborted) return void 0;
331
- if (this.openedAt !== void 0 && require_time.realtimeClock.now() - this.openedAt >= require_time.realtimeTiming.heartbeatInterval) {
323
+ if (this.openedAt !== void 0 && require_wire.realtimeClock.now() - this.openedAt >= require_wire.realtimeTiming.heartbeatInterval) {
332
324
  this.failures = 0;
333
325
  this.lastFailure = void 0;
334
326
  }
@@ -341,7 +333,7 @@ var ReconnectState = class {
341
333
  ...this.cursor === void 0 ? {} : { meta: { cursor: this.cursor } }
342
334
  });
343
335
  const scheduled = observer.reconnect(signal, ++this.attempts, this.delay);
344
- this.delay = Math.min(require_time.realtimeTiming.clientMaxReconnectDelay, this.delay * 2);
336
+ this.delay = Math.min(require_wire.realtimeTiming.clientMaxReconnectDelay, this.delay * 2);
345
337
  return scheduled;
346
338
  }
347
339
  };
@@ -376,7 +368,7 @@ async function requestStream(fetcher, url, retry, signal) {
376
368
  if (retry.cursor !== void 0) headers.set("last-event-id", retry.cursor);
377
369
  const response = await fetchResponse(fetcher, url, headers, signal, retry);
378
370
  if (response === void 0) return void 0;
379
- if (response.body === null || !/^text\/event-stream(?:\s*;|$)/i.test(response.headers.get("content-type") ?? "")) throw require_time.wireInvalid();
371
+ if (response.body === null || !/^text\/event-stream(?:\s*;|$)/i.test(response.headers.get("content-type") ?? "")) throw require_wire.wireInvalid();
380
372
  return response.body;
381
373
  }
382
374
  async function awaitToken(token, signal) {
@@ -424,10 +416,10 @@ async function fetchResponse(fetcher, url, headers, signal, retry) {
424
416
  return response;
425
417
  }
426
418
  function decodeEvent(event, named) {
427
- const raw = parseWireJson(event.data);
419
+ const raw = require_wire.parseWireJson(event.data);
428
420
  if (event.event === "error") {
429
421
  const result = _runlane_contracts_realtime.runRealtimeErrorSchema.safeParse(raw);
430
- if (!result.success) throw require_time.wireInvalid(result.error);
422
+ if (!result.success) throw require_wire.wireInvalid(result.error);
431
423
  const { cursor, ...error } = result.data;
432
424
  throw new _runlane_contracts_realtime.RunlaneError({
433
425
  ...error,
@@ -435,13 +427,13 @@ function decodeEvent(event, named) {
435
427
  });
436
428
  }
437
429
  if (event.event === "end" || event.event === "checkpoint") {
438
- if (!_runlane_contracts_realtime.runRealtimeControlSchema.safeParse(raw).success) throw require_time.wireInvalid();
430
+ if (!_runlane_contracts_realtime.runRealtimeControlSchema.safeParse(raw).success) throw require_wire.wireInvalid();
439
431
  if (event.event === "end") return {
440
432
  kind: "control",
441
433
  terminal: true
442
434
  };
443
435
  const cursor = _runlane_contracts_realtime.runCursorSchema.safeParse(event.id);
444
- if (!cursor.success) throw require_time.wireInvalid(cursor.error);
436
+ if (!cursor.success) throw require_wire.wireInvalid(cursor.error);
445
437
  return {
446
438
  kind: "control",
447
439
  cursor: cursor.data
@@ -451,7 +443,7 @@ function decodeEvent(event, named) {
451
443
  }
452
444
  function decodeNamedEvent(event, raw) {
453
445
  const result = _runlane_contracts_realtime.runStreamWireSchema.safeParse(raw);
454
- if (!result.success || event.event !== "stream" || result.data.cursor !== void 0 && result.data.cursor !== event.id) throw require_time.wireInvalid();
446
+ if (!result.success || event.event !== "stream" || result.data.cursor !== void 0 && result.data.cursor !== event.id) throw require_wire.wireInvalid();
455
447
  return {
456
448
  kind: _runlane_contracts_realtime.RunReaderKind.Stream,
457
449
  value: result.data.record,
@@ -460,7 +452,7 @@ function decodeNamedEvent(event, raw) {
460
452
  }
461
453
  function decodeSubscriptionEvent(event, raw) {
462
454
  const result = _runlane_contracts_realtime.runSubscriptionWireSchema.safeParse(raw);
463
- if (!result.success || String(result.data.type) !== event.event || result.data.cursor !== event.id) throw require_time.wireInvalid();
455
+ if (!result.success || String(result.data.type) !== event.event || result.data.cursor !== event.id) throw require_wire.wireInvalid();
464
456
  return {
465
457
  kind: _runlane_contracts_realtime.RunReaderKind.Subscription,
466
458
  value: result.data,
@@ -469,7 +461,7 @@ function decodeSubscriptionEvent(event, raw) {
469
461
  };
470
462
  }
471
463
  async function responseError(response, signal) {
472
- if (response.body === null) throw require_time.wireInvalid();
464
+ if (response.body === null) throw require_wire.wireInvalid();
473
465
  const reader = response.body.getReader();
474
466
  const decoder = new TextDecoder("utf-8", { fatal: true });
475
467
  let text = "";
@@ -483,12 +475,12 @@ async function responseError(response, signal) {
483
475
  const chunk = await reader.read();
484
476
  if (chunk.done) break;
485
477
  bytes += chunk.value.byteLength;
486
- if (bytes > _runlane_contracts_realtime.realtimeDefaults.maxBufferedBytes) throw require_time.wireInvalid();
478
+ if (bytes > _runlane_contracts_realtime.realtimeDefaults.maxBufferedBytes) throw require_wire.wireInvalid();
487
479
  text += decoder.decode(chunk.value, { stream: true });
488
480
  }
489
- const raw = parseWireJson(text + decoder.decode());
481
+ const raw = require_wire.parseWireJson(text + decoder.decode());
490
482
  const result = realtimeErrorEnvelopeSchema.safeParse(raw);
491
- if (!result.success) throw require_time.wireInvalid(result.error);
483
+ if (!result.success) throw require_wire.wireInvalid(result.error);
492
484
  const { cursor, ...error } = result.data.error;
493
485
  return new _runlane_contracts_realtime.RunlaneError({
494
486
  ...error,
@@ -1 +1 @@
1
- {"version":3,"file":"client.cjs","names":["RunlaneError","ErrorCode","getDownwardJitteredDelayMs","RealtimeConnectionState","RealtimeConnectionCloseReason","encoder","createParser","realtimeDefaults","wireInvalid","RunlaneError","ErrorCode","realtimeDefaults","wireInvalid","z","runRealtimeErrorSchema","createUrlSchema","createFunctionSchema","objectSurfaceSchema","createRunlaneIdSchema","runCursorSchema","RunReaderKind","runStreamNameSchema","invalidOptions","RunlaneError","ErrorCode","RealtimeConnectionState","RunlaneMetricName","RunlaneMetricAttribute","waitForAbortableTimeout","realtimeTiming","realtimeClock","realtimeDefaults","wireInvalid","runRealtimeControlSchema","runStreamWireSchema","runSubscriptionWireSchema","RunSubscriptionEventType","runStatusValues"],"sources":["../src/connection-observer.ts","../src/sse.ts","../src/wire.ts","../src/client.ts"],"sourcesContent":["import {\n ErrorCode,\n RealtimeConnectionCloseReason,\n RealtimeConnectionState,\n RunlaneError,\n type RealtimeConnectionChange,\n} from '@runlane/contracts/realtime'\nimport { getDownwardJitteredDelayMs } from '@runlane/utilities/browser'\n\n/** Owns notification ordering and preserves the first callback failure without recursive reporting. */\nexport class ConnectionObserver {\n failed = false\n\n constructor(private readonly callback: ((change: RealtimeConnectionChange) => void) | undefined) {}\n\n emit(change: RealtimeConnectionChange): void {\n try {\n this.callback?.(change)\n } catch (cause) {\n // Once the observer throws, calling it again could replace the original failure.\n this.failed = true\n throw cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.InternalError,\n message: 'Realtime connection observer failed.',\n cause,\n })\n }\n }\n\n reconnect(signal: AbortSignal, attempt: number, ceilingMs: number): number | undefined {\n if (signal.aborted) return undefined\n const delayMs = getDownwardJitteredDelayMs(ceilingMs)\n this.emit({ state: RealtimeConnectionState.Reconnecting, attempt, delayMs })\n return delayMs\n }\n\n close(signal: AbortSignal, failure: { readonly cause: RunlaneError } | undefined): void {\n if (this.failed) return\n if (failure !== undefined) {\n this.emit({\n state: RealtimeConnectionState.Closed,\n reason: RealtimeConnectionCloseReason.Failed,\n error: failure.cause,\n })\n return\n }\n const reason = signal.aborted ? RealtimeConnectionCloseReason.Aborted : RealtimeConnectionCloseReason.Completed\n this.emit({ state: RealtimeConnectionState.Closed, reason })\n }\n}\n","import { ErrorCode, realtimeDefaults, RunlaneError } from '@runlane/contracts/realtime'\nimport { createParser } from 'eventsource-parser'\n\nimport { wireInvalid } from './errors.js'\n\nconst encoder = new TextEncoder()\n\n/** One parsed SSE event; id retains the preceding checkpoint when omitted by the sender. */\nexport interface SseEvent {\n readonly event: string\n readonly id: string\n readonly data: string\n}\n\n/** Incremental UTF-8 SSE parser; incomplete trailing events are never dispatched. */\nexport async function* readSse(body: ReadableStream<Uint8Array>, signal: AbortSignal): AsyncGenerator<SseEvent, void> {\n const reader = body.getReader()\n const decoder = new TextDecoder('utf-8', { fatal: true })\n let lastId = ''\n const ready: { frame?: SseEvent } = {}\n const budget = new FrameByteBudget()\n const parser = createParser({\n maxBufferSize: realtimeDefaults.maxEventBytes,\n onId(id) {\n lastId = id\n },\n onEvent(message) {\n ready.frame = { event: message.event ?? 'message', id: lastId, data: message.data }\n },\n onError(error) {\n if (error.type === 'max-buffer-size-exceeded') throw wireInvalid(error)\n },\n })\n const abort = () => {\n void reader.cancel().catch(() => undefined)\n }\n signal.addEventListener('abort', abort, { once: true })\n if (signal.aborted) abort()\n try {\n while (!signal.aborted) {\n const result = await readBytes(reader)\n if (result.done) {\n decodeUtf8(decoder)\n return\n }\n for (const char of decodeUtf8(decoder, result.value)) {\n budget.accept(char)\n parser.feed(char)\n if (ready.frame !== undefined) {\n const frame = ready.frame\n delete ready.frame\n yield frame\n }\n }\n }\n } finally {\n signal.removeEventListener('abort', abort)\n // Cancellation may race a disconnected socket; it cannot change the already delivered result.\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n}\n\n// Parser buffers count selected characters; this guard counts every raw UTF-8 field and comment.\nclass FrameByteBudget {\n private retained = 0\n private lineEmpty = true\n private skipLf = false\n private resetAfterCr = false\n\n accept(char: string): void {\n if (this.resetAfterCr && char !== '\\n') {\n this.retained = 0\n this.resetAfterCr = false\n }\n const point = char.codePointAt(0) ?? 0\n this.retained += point < 128 ? 1 : encoder.encode(char).byteLength\n if (this.retained > realtimeDefaults.maxEventBytes) throw wireInvalid()\n if (this.skipLf && char === '\\n') {\n this.skipLf = false\n if (this.resetAfterCr) {\n this.retained = 0\n this.resetAfterCr = false\n }\n return\n }\n this.skipLf = char === '\\r'\n if (char !== '\\r' && char !== '\\n') {\n this.lineEmpty = false\n return\n }\n if (this.lineEmpty && char === '\\n') this.retained = 0\n this.resetAfterCr = this.lineEmpty && char === '\\r'\n this.lineEmpty = true\n }\n}\n\nasync function readBytes(reader: ReadableStreamDefaultReader<Uint8Array>) {\n try {\n return await reader.read()\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection was interrupted.',\n retryable: true,\n cause,\n })\n }\n}\n\nfunction decodeUtf8(decoder: TextDecoder, bytes?: Uint8Array): string {\n try {\n return bytes === undefined ? decoder.decode() : decoder.decode(bytes, { stream: true })\n } catch (cause) {\n throw wireInvalid(cause)\n }\n}\n","import { realtimeDefaults } from '@runlane/contracts/realtime'\n\nimport { wireInvalid } from './errors.js'\n\nconst encoder = new TextEncoder()\n\n/** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */\nexport function parseWireJson(text: string): unknown {\n try {\n if (encoder.encode(text).byteLength > realtimeDefaults.maxEventBytes) throw wireInvalid()\n return JSON.parse(text)\n } catch (cause) {\n throw wireInvalid(cause)\n }\n}\n","import {\n createRunlaneIdSchema,\n ErrorCode,\n RealtimeConnectionState,\n realtimeDefaults,\n recordRunlaneTelemetryMetric,\n runCursorSchema,\n RunlaneError,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunReaderKind,\n runRealtimeControlSchema,\n runRealtimeErrorSchema,\n runStatusValues,\n runStreamNameSchema,\n runStreamWireSchema,\n RunSubscriptionEventType,\n runSubscriptionWireSchema,\n type RealtimeConnectionChange,\n type RunCursor,\n type RunId,\n type RunlaneIdInput,\n type RunlaneTelemetryRecordingContext,\n type RunStreamName,\n type RunStreamPart,\n type RunStreamRecord,\n type RunSubscribeOptions,\n type RunSubscriptionEvent,\n} from '@runlane/contracts/realtime'\nimport {\n createFunctionSchema,\n createUrlSchema,\n objectSurfaceSchema,\n waitForAbortableTimeout,\n type Awaitable,\n} from '@runlane/utilities/browser'\nimport * as z from 'zod'\n\nimport { ConnectionObserver } from './connection-observer.js'\nimport { invalidOptions, wireInvalid } from './errors.js'\nimport { readSse, type SseEvent } from './sse.js'\nimport { realtimeClock, realtimeTiming } from './time.js'\nimport { parseWireJson } from './wire.js'\n\n/** Run and cancellation context for an initial token request or a refresh after denial. */\nexport interface RunTokenRequest {\n readonly runId: RunId\n readonly signal: AbortSignal\n}\n\n/** Browser/Node Fetch client; the application owns its token refresh callback and lifetime. */\nexport interface RunlaneClientOptions extends RunlaneTelemetryRecordingContext {\n readonly baseUrl: string\n /** Requests an initial token when missing, or refreshes once after HTTP access denial. */\n readonly refreshAccessToken?: (request: RunTokenRequest) => Awaitable<string>\n readonly fetch?: typeof globalThis.fetch\n}\n/** Initial token, resume cursor, cancellation, and connection notifications shared by both readers. */\nexport type RunlaneClientReadOptions = Pick<RunSubscribeOptions, 'after' | 'signal'> & {\n readonly accessToken?: string\n readonly onConnectionChange?: (change: RealtimeConnectionChange) => void\n}\n/** Pull-based readers validate input on the first next(), before effects. Task generics add types only; abort ends normally. */\nexport interface RunlaneClient {\n subscribe<TTask = unknown>(\n runId: RunlaneIdInput,\n options?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunSubscriptionEvent<TTask>, void>\n /** Supply TName explicitly for an exact chunk type when TTask declares several streams. */\n readStream<TTask = unknown, TName extends RunStreamName<TTask> = RunStreamName<TTask>>(\n runId: RunlaneIdInput,\n name: TName,\n options?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord<RunStreamPart<TTask, TName>>, void>\n}\nconst realtimeErrorEnvelopeSchema = z.object({ error: runRealtimeErrorSchema })\n\ntype Delivered =\n | {\n readonly kind: RunReaderKind.Subscription\n readonly value: RunSubscriptionEvent\n readonly cursor: RunCursor\n readonly terminal?: boolean\n }\n | {\n readonly kind: RunReaderKind.Stream\n readonly value: RunStreamRecord\n readonly cursor?: RunCursor\n readonly terminal?: false\n }\n | { readonly kind: 'control'; readonly value?: never; readonly cursor?: RunCursor; readonly terminal?: boolean }\n\nconst clientOptionsSchema = z.strictObject({\n baseUrl: createUrlSchema('baseUrl must be an absolute HTTP or HTTPS URL.')\n .refine((base) => base.protocol === 'https:' || base.protocol === 'http:', 'baseUrl must use HTTP or HTTPS.')\n .refine(\n (base) => !base.username && !base.password && !base.search && !base.hash,\n 'baseUrl must not contain credentials, a query, or a fragment.',\n ),\n refreshAccessToken: createFunctionSchema<NonNullable<RunlaneClientOptions['refreshAccessToken']>>(\n 'refreshAccessToken must be a function.',\n ).optional(),\n fetch: createFunctionSchema<typeof fetch>('fetch must be a function.').optional(),\n telemetry: objectSurfaceSchema.optional(),\n onTelemetryError: createFunctionSchema<NonNullable<RunlaneClientOptions['onTelemetryError']>>(\n 'onTelemetryError must be a function.',\n ).optional(),\n})\n\nconst readerFields = {\n runId: createRunlaneIdSchema<'run'>('Run id'),\n after: runCursorSchema.optional(),\n}\nconst readerRequestSchema = z.discriminatedUnion('kind', [\n z.object({ ...readerFields, kind: z.literal(RunReaderKind.Subscription), name: z.undefined() }),\n z.object({ ...readerFields, kind: z.literal(RunReaderKind.Stream), name: runStreamNameSchema }),\n])\n\n/** Creates a reusable authenticated streaming client with bounded parsing and reconnect delays. */\nexport function createRunlaneClient(options: RunlaneClientOptions): RunlaneClient {\n const checked = clientOptionsSchema.safeParse(options)\n if (!checked.success) throw invalidOptions(checked.error, 'client')\n const base = checked.data.baseUrl\n const fetcher = options.fetch ?? globalThis.fetch\n function subscribe<TTask = unknown>(\n runId: RunlaneIdInput,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunSubscriptionEvent<TTask>, void>\n async function* subscribe(\n runId: RunlaneIdInput,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunSubscriptionEvent, void> {\n for await (const event of connect(options, fetcher, base, runId, undefined, RunReaderKind.Subscription, input)) {\n if (event.kind === RunReaderKind.Subscription) yield event.value\n }\n }\n function readStream<TTask = unknown, TName extends RunStreamName<TTask> = RunStreamName<TTask>>(\n runId: RunlaneIdInput,\n name: TName,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord<RunStreamPart<TTask, TName>>, void>\n async function* readStream(\n runId: RunlaneIdInput,\n name: string,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord, void> {\n for await (const event of connect(options, fetcher, base, runId, name, RunReaderKind.Stream, input)) {\n if (event.kind === RunReaderKind.Stream) yield event.value\n }\n }\n return { subscribe, readStream }\n}\n\nasync function* connect(\n options: RunlaneClientOptions,\n fetcher: typeof fetch,\n base: URL,\n runId: RunlaneIdInput,\n name: string | undefined,\n kind: RunReaderKind.Subscription | RunReaderKind.Stream,\n input: RunlaneClientReadOptions = {},\n): AsyncGenerator<Delivered, void> {\n const checked = readerRequestSchema.safeParse({ kind, runId, name, after: input.after })\n if (!checked.success)\n throw new RunlaneError({\n code: checked.error.issues[0]?.path[0] === 'after' ? ErrorCode.RunCursorInvalid : ErrorCode.ValidationFailed,\n message: 'Run id, stream name, or after cursor is invalid.',\n cause: checked.error,\n })\n const request = checked.data\n const url = makeUrl(base, request.runId, request.name)\n const signal = input.signal ?? new AbortController().signal\n const observer = new ConnectionObserver(input.onConnectionChange)\n let failure: { readonly cause: RunlaneError } | undefined\n try {\n yield* followConnections(\n options,\n fetcher,\n url,\n request.runId,\n kind,\n request.after,\n input.accessToken,\n signal,\n observer,\n )\n } catch (cause) {\n const error =\n cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.InternalError,\n message: 'Realtime reader failed.',\n cause,\n })\n failure = { cause: error }\n throw error\n } finally {\n observer.close(signal, failure)\n }\n}\n\nasync function* followConnections(\n options: RunlaneClientOptions,\n fetcher: typeof fetch,\n url: URL,\n runId: RunId,\n kind: RunReaderKind.Subscription | RunReaderKind.Stream,\n after: RunCursor | undefined,\n accessToken: string | undefined,\n signal: AbortSignal,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n const retry = new ReconnectState(after, accessToken, options.refreshAccessToken)\n const named = kind === RunReaderKind.Stream\n const operation = named ? 'read' : 'subscribe'\n while (!signal.aborted) {\n observer.emit({ state: RealtimeConnectionState.Connecting })\n for await (const delivered of connectionEvents(fetcher, url, runId, retry, signal, named, observer)) {\n const duplicate = delivered.kind === RunReaderKind.Stream && !retry.deliverRecord(delivered.value.id)\n if (!duplicate && delivered.value !== undefined) yield delivered\n // Resume only after the caller has received the value.\n retry.delivered(delivered.cursor)\n if (delivered.terminal) return\n }\n const scheduled = retry.schedule(signal, observer)\n if (scheduled === undefined) return\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeReconnectCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation },\n })\n await waitForAbortableTimeout(scheduled, signal)\n }\n}\n\n// One owner for the current token, delivered checkpoint, and consecutive-failure budget.\nclass ReconnectState {\n cursor: RunCursor | undefined\n private readonly records = new Set<RunStreamRecord['id']>()\n private delay = realtimeTiming.clientReconnectDelay\n private attempts = 0\n private failures = 0\n private openedAt: number | undefined\n lastFailure: RunlaneError | undefined\n private needsRefresh: boolean\n private refreshedAfterDenial = false\n constructor(\n after: RunCursor | undefined,\n public accessToken: string | undefined,\n private readonly refreshAccessToken: RunlaneClientOptions['refreshAccessToken'],\n ) {\n this.cursor = after\n this.needsRefresh = accessToken === undefined && refreshAccessToken !== undefined\n }\n async readyToken(runId: RunId, signal: AbortSignal): Promise<boolean> {\n if (!this.needsRefresh || this.refreshAccessToken === undefined) return true\n try {\n signal.throwIfAborted()\n const token = await awaitToken(this.refreshAccessToken({ runId, signal }), signal)\n signal.throwIfAborted()\n this.accessToken = token\n this.needsRefresh = false\n return true\n } catch (cause) {\n if (signal.aborted) return false\n if (cause instanceof RunlaneError && !cause.retryable) throw cause\n this.lastFailure =\n cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime token refresh is temporarily unavailable.',\n retryable: true,\n cause,\n })\n return false\n }\n }\n refreshAfterDenial(status: number, error: RunlaneError): boolean {\n if (status !== 403 || error.code !== ErrorCode.AccessDenied) return false\n if (this.refreshAccessToken === undefined || this.refreshedAfterDenial) return false\n this.needsRefresh = true\n this.refreshedAfterDenial = true\n return true\n }\n open(): void {\n this.refreshedAfterDenial = false\n this.attempts = 0\n this.delay = realtimeTiming.clientReconnectDelay\n this.openedAt = realtimeClock.now()\n }\n deliverRecord(id: RunStreamRecord['id']): boolean {\n if (this.records.has(id)) return false\n this.records.add(id)\n return true\n }\n delivered(cursor: RunCursor | undefined): void {\n if (cursor === undefined || cursor === this.cursor) return\n this.cursor = cursor\n this.records.clear()\n this.failures = 0\n this.lastFailure = undefined\n this.attempts = 0\n this.delay = realtimeTiming.clientReconnectDelay\n }\n schedule(signal: AbortSignal, observer: ConnectionObserver): number | undefined {\n if (signal.aborted) return undefined\n // A healthy idle connection can rotate for hours without producing a new run cursor.\n if (this.openedAt !== undefined && realtimeClock.now() - this.openedAt >= realtimeTiming.heartbeatInterval) {\n this.failures = 0\n this.lastFailure = undefined\n }\n this.openedAt = undefined\n if (++this.failures >= realtimeDefaults.clientMaxReconnectAttempts)\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection repeatedly failed without progress.',\n retryable: false,\n cause: this.lastFailure,\n ...(this.cursor === undefined ? {} : { meta: { cursor: this.cursor } }),\n })\n const scheduled = observer.reconnect(signal, ++this.attempts, this.delay)\n this.delay = Math.min(realtimeTiming.clientMaxReconnectDelay, this.delay * 2)\n return scheduled\n }\n}\n\nasync function* connectionEvents(\n fetcher: typeof fetch,\n url: URL,\n runId: RunId,\n retry: ReconnectState,\n signal: AbortSignal,\n named: boolean,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n // Permanent refresher errors bypass the retryable I/O catch.\n if (!(await retry.readyToken(runId, signal))) return\n yield* readConnection(fetcher, url, retry, signal, named, observer)\n}\n\nasync function* readConnection(\n fetcher: typeof fetch,\n url: URL,\n retry: ReconnectState,\n signal: AbortSignal,\n named: boolean,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n let body: ReadableStream<Uint8Array> | undefined\n try {\n body = await requestStream(fetcher, url, retry, signal)\n if (body === undefined) return\n retry.open()\n observer.emit({ state: RealtimeConnectionState.Open })\n for await (const event of readSse(body, signal)) yield decodeEvent(event, named)\n } catch (cause) {\n if (observer.failed) throw cause\n if (signal.aborted) return\n if (cause instanceof RunlaneError && cause.retryable) {\n retry.lastFailure = cause\n return\n }\n throw cause\n } finally {\n if (body !== undefined && !body.locked) await body.cancel().catch(() => undefined)\n }\n}\n\nasync function requestStream(\n fetcher: typeof fetch,\n url: URL,\n retry: ReconnectState,\n signal: AbortSignal,\n): Promise<ReadableStream<Uint8Array> | undefined> {\n signal.throwIfAborted()\n const headers = new Headers({ accept: 'text/event-stream' })\n if (retry.accessToken !== undefined) headers.set('authorization', `Bearer ${retry.accessToken}`)\n if (retry.cursor !== undefined) headers.set('last-event-id', retry.cursor)\n const response = await fetchResponse(fetcher, url, headers, signal, retry)\n if (response === undefined) return undefined\n if (response.body === null || !/^text\\/event-stream(?:\\s*;|$)/i.test(response.headers.get('content-type') ?? ''))\n throw wireInvalid()\n return response.body\n}\n\nasync function awaitToken(token: Awaitable<string>, signal: AbortSignal): Promise<string> {\n const aborted = Promise.withResolvers<never>()\n const abort = () => aborted.reject(signal.reason)\n signal.addEventListener('abort', abort, { once: true })\n if (signal.aborted) abort()\n try {\n // The race observes late token rejection even after abort wins.\n return await Promise.race([token, aborted.promise])\n } finally {\n signal.removeEventListener('abort', abort)\n }\n}\n\nasync function fetchResponse(\n fetcher: typeof fetch,\n url: URL,\n headers: Headers,\n signal: AbortSignal,\n retry: ReconnectState,\n): Promise<Response | undefined> {\n let response: Response\n try {\n response = await fetcher(url, { headers, signal, cache: 'no-store', redirect: 'error' })\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection was interrupted.',\n retryable: true,\n cause,\n })\n }\n if (response.status >= 500 && response.headers.get('content-type')?.includes('application/json'))\n throw await responseError(response, signal)\n if (response.status === 429 || response.status >= 500) {\n await response.body?.cancel()\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime server is temporarily unavailable.',\n retryable: true,\n })\n }\n if (!response.ok) {\n const error = await responseError(response, signal)\n if (retry.refreshAfterDenial(response.status, error)) return undefined\n throw error\n }\n return response\n}\n\nfunction decodeEvent(event: SseEvent, named: boolean): Delivered {\n const raw = parseWireJson(event.data)\n if (event.event === 'error') {\n const result = runRealtimeErrorSchema.safeParse(raw)\n if (!result.success) throw wireInvalid(result.error)\n const { cursor, ...error } = result.data\n throw new RunlaneError({ ...error, ...(cursor === undefined ? {} : { meta: { cursor } }) })\n }\n if (event.event === 'end' || event.event === 'checkpoint') {\n if (!runRealtimeControlSchema.safeParse(raw).success) throw wireInvalid()\n if (event.event === 'end') return { kind: 'control', terminal: true }\n const cursor = runCursorSchema.safeParse(event.id)\n if (!cursor.success) throw wireInvalid(cursor.error)\n return { kind: 'control', cursor: cursor.data }\n }\n return named ? decodeNamedEvent(event, raw) : decodeSubscriptionEvent(event, raw)\n}\n\nfunction decodeNamedEvent(event: SseEvent, raw: unknown): Delivered {\n const result = runStreamWireSchema.safeParse(raw)\n if (\n !result.success ||\n event.event !== 'stream' ||\n (result.data.cursor !== undefined && result.data.cursor !== event.id)\n )\n throw wireInvalid()\n return { kind: RunReaderKind.Stream, value: result.data.record, cursor: result.data.cursor }\n}\n\nfunction decodeSubscriptionEvent(event: SseEvent, raw: unknown): Delivered {\n const result = runSubscriptionWireSchema.safeParse(raw)\n if (!result.success || String(result.data.type) !== event.event || result.data.cursor !== event.id)\n throw wireInvalid()\n return {\n kind: RunReaderKind.Subscription,\n value: result.data,\n cursor: result.data.cursor,\n terminal: result.data.type === RunSubscriptionEventType.Status && runStatusValues.isTerminal(result.data.status),\n }\n}\n\nasync function responseError(response: Response, signal: AbortSignal): Promise<RunlaneError> {\n if (response.body === null) throw wireInvalid()\n const reader = response.body.getReader()\n const decoder = new TextDecoder('utf-8', { fatal: true })\n let text = ''\n let bytes = 0\n const abort = () => {\n void reader.cancel().catch(() => undefined)\n }\n signal.addEventListener('abort', abort, { once: true })\n try {\n while (!signal.aborted) {\n const chunk = await reader.read()\n if (chunk.done) break\n bytes += chunk.value.byteLength\n if (bytes > realtimeDefaults.maxBufferedBytes) throw wireInvalid()\n text += decoder.decode(chunk.value, { stream: true })\n }\n const raw = parseWireJson(text + decoder.decode())\n const result = realtimeErrorEnvelopeSchema.safeParse(raw)\n if (!result.success) throw wireInvalid(result.error)\n const { cursor, ...error } = result.data.error\n return new RunlaneError({\n ...error,\n ...(cursor === undefined ? {} : { meta: { cursor } }),\n retryable: response.status >= 500 && result.data.error.retryable,\n })\n } finally {\n signal.removeEventListener('abort', abort)\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n}\n\nfunction makeUrl(base: URL, runId: RunId, name?: string): URL {\n try {\n const path = name === undefined ? 'events' : `streams/${encodeURIComponent(name)}`\n return new URL(`${base.href.replace(/\\/$/, '')}/runs/${encodeURIComponent(runId)}/${path}`)\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.ValidationFailed,\n message: 'Run id or stream name cannot be encoded in a URL.',\n cause,\n })\n }\n}\n\nexport {\n ErrorCode,\n RunlaneError,\n RunSubscriptionEventType,\n RunStreamRecordType,\n type RunSubscriptionEvent,\n type RunStreamRecord,\n type RunCursor,\n} from '@runlane/contracts/realtime'\n\nexport type {\n RunTypes,\n RunOutput,\n RunMeta,\n RunStreams,\n RunStreamName,\n RunStreamPart,\n} from '@runlane/contracts/realtime'\n"],"mappings":"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"}
1
+ {"version":3,"file":"client.cjs","names":["RunlaneError","ErrorCode","getDownwardJitteredDelayMs","RealtimeConnectionState","RealtimeConnectionCloseReason","createParser","realtimeDefaults","wireInvalid","RunlaneError","ErrorCode","z","runRealtimeErrorSchema","createUrlSchema","createFunctionSchema","objectSurfaceSchema","createRunlaneIdSchema","runCursorSchema","RunReaderKind","runStreamNameSchema","invalidOptions","RunlaneError","ErrorCode","streamSelectionQuery","RealtimeConnectionState","RunlaneMetricName","RunlaneMetricAttribute","waitForAbortableTimeout","realtimeTiming","realtimeClock","realtimeDefaults","wireInvalid","parseWireJson","runRealtimeControlSchema","runStreamWireSchema","runSubscriptionWireSchema","RunSubscriptionEventType","runStatusValues"],"sources":["../src/connection-observer.ts","../src/sse.ts","../src/client.ts"],"sourcesContent":["import {\n ErrorCode,\n RealtimeConnectionCloseReason,\n RealtimeConnectionState,\n RunlaneError,\n type RealtimeConnectionChange,\n} from '@runlane/contracts/realtime'\nimport { getDownwardJitteredDelayMs } from '@runlane/utilities/browser'\n\n/** Owns notification ordering and preserves the first callback failure without recursive reporting. */\nexport class ConnectionObserver {\n failed = false\n\n constructor(private readonly callback: ((change: RealtimeConnectionChange) => void) | undefined) {}\n\n emit(change: RealtimeConnectionChange): void {\n try {\n this.callback?.(change)\n } catch (cause) {\n // Once the observer throws, calling it again could replace the original failure.\n this.failed = true\n throw cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.InternalError,\n message: 'Realtime connection observer failed.',\n cause,\n })\n }\n }\n\n reconnect(signal: AbortSignal, attempt: number, ceilingMs: number): number | undefined {\n if (signal.aborted) return undefined\n const delayMs = getDownwardJitteredDelayMs(ceilingMs)\n this.emit({ state: RealtimeConnectionState.Reconnecting, attempt, delayMs })\n return delayMs\n }\n\n close(signal: AbortSignal, failure: { readonly cause: RunlaneError } | undefined): void {\n if (this.failed) return\n if (failure !== undefined) {\n this.emit({\n state: RealtimeConnectionState.Closed,\n reason: RealtimeConnectionCloseReason.Failed,\n error: failure.cause,\n })\n return\n }\n const reason = signal.aborted ? RealtimeConnectionCloseReason.Aborted : RealtimeConnectionCloseReason.Completed\n this.emit({ state: RealtimeConnectionState.Closed, reason })\n }\n}\n","import { ErrorCode, realtimeDefaults, RunlaneError } from '@runlane/contracts/realtime'\nimport { createParser } from 'eventsource-parser'\n\nimport { wireInvalid } from './errors.js'\n\nconst encoder = new TextEncoder()\n\n/** One parsed SSE event; id retains the preceding checkpoint when omitted by the sender. */\nexport interface SseEvent {\n readonly event: string\n readonly id: string\n readonly data: string\n}\n\n/** Incremental UTF-8 SSE parser; incomplete trailing events are never dispatched. */\nexport async function* readSse(body: ReadableStream<Uint8Array>, signal: AbortSignal): AsyncGenerator<SseEvent, void> {\n const reader = body.getReader()\n const decoder = new TextDecoder('utf-8', { fatal: true })\n let lastId = ''\n const ready: { frame?: SseEvent } = {}\n const budget = new FrameByteBudget()\n const parser = createParser({\n maxBufferSize: realtimeDefaults.maxEventBytes,\n onId(id) {\n lastId = id\n },\n onEvent(message) {\n ready.frame = { event: message.event ?? 'message', id: lastId, data: message.data }\n },\n onError(error) {\n if (error.type === 'max-buffer-size-exceeded') throw wireInvalid(error)\n },\n })\n const abort = () => {\n void reader.cancel().catch(() => undefined)\n }\n signal.addEventListener('abort', abort, { once: true })\n if (signal.aborted) abort()\n try {\n while (!signal.aborted) {\n const result = await readBytes(reader)\n if (result.done) {\n decodeUtf8(decoder)\n return\n }\n for (const char of decodeUtf8(decoder, result.value)) {\n budget.accept(char)\n parser.feed(char)\n if (ready.frame !== undefined) {\n const frame = ready.frame\n delete ready.frame\n yield frame\n }\n }\n }\n } finally {\n signal.removeEventListener('abort', abort)\n // Cancellation may race a disconnected socket; it cannot change the already delivered result.\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n}\n\n// Parser buffers count selected characters; this guard counts every raw UTF-8 field and comment.\nclass FrameByteBudget {\n private retained = 0\n private lineEmpty = true\n private skipLf = false\n private resetAfterCr = false\n\n accept(char: string): void {\n if (this.resetAfterCr && char !== '\\n') {\n this.retained = 0\n this.resetAfterCr = false\n }\n const point = char.codePointAt(0) ?? 0\n this.retained += point < 128 ? 1 : encoder.encode(char).byteLength\n if (this.retained > realtimeDefaults.maxEventBytes) throw wireInvalid()\n if (this.skipLf && char === '\\n') {\n this.skipLf = false\n if (this.resetAfterCr) {\n this.retained = 0\n this.resetAfterCr = false\n }\n return\n }\n this.skipLf = char === '\\r'\n if (char !== '\\r' && char !== '\\n') {\n this.lineEmpty = false\n return\n }\n if (this.lineEmpty && char === '\\n') this.retained = 0\n this.resetAfterCr = this.lineEmpty && char === '\\r'\n this.lineEmpty = true\n }\n}\n\nasync function readBytes(reader: ReadableStreamDefaultReader<Uint8Array>) {\n try {\n return await reader.read()\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection was interrupted.',\n retryable: true,\n cause,\n })\n }\n}\n\nfunction decodeUtf8(decoder: TextDecoder, bytes?: Uint8Array): string {\n try {\n return bytes === undefined ? decoder.decode() : decoder.decode(bytes, { stream: true })\n } catch (cause) {\n throw wireInvalid(cause)\n }\n}\n","import {\n createRunlaneIdSchema,\n ErrorCode,\n RealtimeConnectionState,\n realtimeDefaults,\n recordRunlaneTelemetryMetric,\n runCursorSchema,\n RunlaneError,\n RunlaneMetricAttribute,\n RunlaneMetricName,\n RunReaderKind,\n runRealtimeControlSchema,\n runRealtimeErrorSchema,\n runStatusValues,\n runStreamNameSchema,\n runStreamWireSchema,\n RunSubscriptionEventType,\n runSubscriptionWireSchema,\n type RealtimeConnectionChange,\n type RunCursor,\n type RunId,\n type RunlaneIdInput,\n type RunlaneTelemetryRecordingContext,\n type RunStreamName,\n type RunStreamPart,\n type RunStreamRecord,\n type RunSubscribeOptions,\n type RunSubscriptionEvent,\n} from '@runlane/contracts/realtime'\nimport {\n createFunctionSchema,\n createUrlSchema,\n objectSurfaceSchema,\n waitForAbortableTimeout,\n type Awaitable,\n} from '@runlane/utilities/browser'\nimport * as z from 'zod'\n\nimport { ConnectionObserver } from './connection-observer.js'\nimport { invalidOptions, wireInvalid } from './errors.js'\nimport { readSse, type SseEvent } from './sse.js'\nimport { realtimeClock, realtimeTiming } from './time.js'\nimport { parseWireJson, streamSelectionQuery } from './wire.js'\n\n/** Run and cancellation context for an initial token request or a refresh after denial. */\nexport interface RunTokenRequest {\n readonly runId: RunId\n readonly signal: AbortSignal\n}\n\n/** Browser/Node Fetch client; the application owns its token refresh callback and lifetime. */\nexport interface RunlaneClientOptions extends RunlaneTelemetryRecordingContext {\n readonly baseUrl: string\n /** Requests an initial token when missing, or refreshes once after HTTP access denial. */\n readonly refreshAccessToken?: (request: RunTokenRequest) => Awaitable<string>\n readonly fetch?: typeof globalThis.fetch\n}\n/** Initial token, resume cursor, cancellation, and connection notifications shared by both readers. */\nexport type RunlaneClientReadOptions = Pick<RunSubscribeOptions, 'after' | 'signal'> & {\n readonly accessToken?: string\n readonly onConnectionChange?: (change: RealtimeConnectionChange) => void\n}\n/** Subscription controls; omit streams to read all streams permitted by the grant. */\nexport type RunlaneClientSubscribeOptions = RunlaneClientReadOptions & {\n readonly streams?: false\n}\n/** Pull-based readers validate input on the first next(), before effects. Task generics add types only; abort ends normally. */\nexport interface RunlaneClient {\n subscribe<TTask = unknown>(\n runId: RunlaneIdInput,\n options?: RunlaneClientSubscribeOptions,\n ): AsyncGenerator<RunSubscriptionEvent<TTask>, void>\n /** Supply TName explicitly for an exact chunk type when TTask declares several streams. */\n readStream<TTask = unknown, TName extends RunStreamName<TTask> = RunStreamName<TTask>>(\n runId: RunlaneIdInput,\n name: TName,\n options?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord<RunStreamPart<TTask, TName>>, void>\n}\nconst realtimeErrorEnvelopeSchema = z.object({ error: runRealtimeErrorSchema })\n\ntype Delivered =\n | {\n readonly kind: RunReaderKind.Subscription\n readonly value: RunSubscriptionEvent\n readonly cursor: RunCursor\n readonly terminal?: boolean\n }\n | {\n readonly kind: RunReaderKind.Stream\n readonly value: RunStreamRecord\n readonly cursor?: RunCursor\n readonly terminal?: false\n }\n | { readonly kind: 'control'; readonly value?: never; readonly cursor?: RunCursor; readonly terminal?: boolean }\n\nconst clientOptionsSchema = z.strictObject({\n baseUrl: createUrlSchema('baseUrl must be an absolute HTTP or HTTPS URL.')\n .refine((base) => base.protocol === 'https:' || base.protocol === 'http:', 'baseUrl must use HTTP or HTTPS.')\n .refine(\n (base) => !base.username && !base.password && !base.search && !base.hash,\n 'baseUrl must not contain credentials, a query, or a fragment.',\n ),\n refreshAccessToken: createFunctionSchema<NonNullable<RunlaneClientOptions['refreshAccessToken']>>(\n 'refreshAccessToken must be a function.',\n ).optional(),\n fetch: createFunctionSchema<typeof fetch>('fetch must be a function.').optional(),\n telemetry: objectSurfaceSchema.optional(),\n onTelemetryError: createFunctionSchema<NonNullable<RunlaneClientOptions['onTelemetryError']>>(\n 'onTelemetryError must be a function.',\n ).optional(),\n})\n\nconst readerFields = {\n runId: createRunlaneIdSchema<'run'>('Run id'),\n after: runCursorSchema.optional(),\n}\nconst readerRequestSchema = z.discriminatedUnion('kind', [\n z.object({\n ...readerFields,\n kind: z.literal(RunReaderKind.Subscription),\n name: z.undefined(),\n streams: z.literal(false).optional(),\n }),\n z.object({ ...readerFields, kind: z.literal(RunReaderKind.Stream), name: runStreamNameSchema }),\n])\n\n/** Creates a reusable authenticated streaming client with bounded parsing and reconnect delays. */\nexport function createRunlaneClient(options: RunlaneClientOptions): RunlaneClient {\n const checked = clientOptionsSchema.safeParse(options)\n if (!checked.success) throw invalidOptions(checked.error, 'client')\n const base = checked.data.baseUrl\n const fetcher = options.fetch ?? globalThis.fetch\n function subscribe<TTask = unknown>(\n runId: RunlaneIdInput,\n input?: RunlaneClientSubscribeOptions,\n ): AsyncGenerator<RunSubscriptionEvent<TTask>, void>\n async function* subscribe(\n runId: RunlaneIdInput,\n input?: RunlaneClientSubscribeOptions,\n ): AsyncGenerator<RunSubscriptionEvent, void> {\n for await (const event of connect(options, fetcher, base, runId, undefined, RunReaderKind.Subscription, input)) {\n if (event.kind === RunReaderKind.Subscription) yield event.value\n }\n }\n function readStream<TTask = unknown, TName extends RunStreamName<TTask> = RunStreamName<TTask>>(\n runId: RunlaneIdInput,\n name: TName,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord<RunStreamPart<TTask, TName>>, void>\n async function* readStream(\n runId: RunlaneIdInput,\n name: string,\n input?: RunlaneClientReadOptions,\n ): AsyncGenerator<RunStreamRecord, void> {\n for await (const event of connect(options, fetcher, base, runId, name, RunReaderKind.Stream, input)) {\n if (event.kind === RunReaderKind.Stream) yield event.value\n }\n }\n return { subscribe, readStream }\n}\n\nasync function* connect(\n options: RunlaneClientOptions,\n fetcher: typeof fetch,\n base: URL,\n runId: RunlaneIdInput,\n name: string | undefined,\n kind: RunReaderKind.Subscription | RunReaderKind.Stream,\n input: RunlaneClientSubscribeOptions = {},\n): AsyncGenerator<Delivered, void> {\n const checked = readerRequestSchema.safeParse({ kind, runId, name, after: input.after, streams: input.streams })\n if (!checked.success)\n throw new RunlaneError({\n code: checked.error.issues[0]?.path[0] === 'after' ? ErrorCode.RunCursorInvalid : ErrorCode.ValidationFailed,\n message: 'Run id, stream name, stream selection, or after cursor is invalid.',\n cause: checked.error,\n })\n const request = checked.data\n const url = makeUrl(base, request.runId, request.name)\n if (request.kind === RunReaderKind.Subscription && request.streams === false)\n url.searchParams.set(streamSelectionQuery.name, streamSelectionQuery.none)\n const signal = input.signal ?? new AbortController().signal\n const observer = new ConnectionObserver(input.onConnectionChange)\n let failure: { readonly cause: RunlaneError } | undefined\n try {\n yield* followConnections(\n options,\n fetcher,\n url,\n request.runId,\n kind,\n request.after,\n input.accessToken,\n signal,\n observer,\n )\n } catch (cause) {\n const error =\n cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.InternalError,\n message: 'Realtime reader failed.',\n cause,\n })\n failure = { cause: error }\n throw error\n } finally {\n observer.close(signal, failure)\n }\n}\n\nasync function* followConnections(\n options: RunlaneClientOptions,\n fetcher: typeof fetch,\n url: URL,\n runId: RunId,\n kind: RunReaderKind.Subscription | RunReaderKind.Stream,\n after: RunCursor | undefined,\n accessToken: string | undefined,\n signal: AbortSignal,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n const retry = new ReconnectState(after, accessToken, options.refreshAccessToken)\n const named = kind === RunReaderKind.Stream\n const operation = named ? 'read' : 'subscribe'\n while (!signal.aborted) {\n observer.emit({ state: RealtimeConnectionState.Connecting })\n for await (const delivered of connectionEvents(fetcher, url, runId, retry, signal, named, observer)) {\n const duplicate = delivered.kind === RunReaderKind.Stream && !retry.deliverRecord(delivered.value.id)\n if (!duplicate && delivered.value !== undefined) yield delivered\n // Resume only after the caller has received the value.\n retry.delivered(delivered.cursor)\n if (delivered.terminal) return\n }\n const scheduled = retry.schedule(signal, observer)\n if (scheduled === undefined) return\n recordRunlaneTelemetryMetric(options, {\n name: RunlaneMetricName.RealtimeReconnectCount,\n value: 1,\n attributes: { [RunlaneMetricAttribute.Operation]: operation },\n })\n await waitForAbortableTimeout(scheduled, signal)\n }\n}\n\n// One owner for the current token, delivered checkpoint, and consecutive-failure budget.\nclass ReconnectState {\n cursor: RunCursor | undefined\n private readonly records = new Set<RunStreamRecord['id']>()\n private delay = realtimeTiming.clientReconnectDelay\n private attempts = 0\n private failures = 0\n private openedAt: number | undefined\n lastFailure: RunlaneError | undefined\n private needsRefresh: boolean\n private refreshedAfterDenial = false\n constructor(\n after: RunCursor | undefined,\n public accessToken: string | undefined,\n private readonly refreshAccessToken: RunlaneClientOptions['refreshAccessToken'],\n ) {\n this.cursor = after\n this.needsRefresh = accessToken === undefined && refreshAccessToken !== undefined\n }\n async readyToken(runId: RunId, signal: AbortSignal): Promise<boolean> {\n if (!this.needsRefresh || this.refreshAccessToken === undefined) return true\n try {\n signal.throwIfAborted()\n const token = await awaitToken(this.refreshAccessToken({ runId, signal }), signal)\n signal.throwIfAborted()\n this.accessToken = token\n this.needsRefresh = false\n return true\n } catch (cause) {\n if (signal.aborted) return false\n if (cause instanceof RunlaneError && !cause.retryable) throw cause\n this.lastFailure =\n cause instanceof RunlaneError\n ? cause\n : new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime token refresh is temporarily unavailable.',\n retryable: true,\n cause,\n })\n return false\n }\n }\n refreshAfterDenial(status: number, error: RunlaneError): boolean {\n if (status !== 403 || error.code !== ErrorCode.AccessDenied) return false\n if (this.refreshAccessToken === undefined || this.refreshedAfterDenial) return false\n this.needsRefresh = true\n this.refreshedAfterDenial = true\n return true\n }\n open(): void {\n this.refreshedAfterDenial = false\n this.attempts = 0\n this.delay = realtimeTiming.clientReconnectDelay\n this.openedAt = realtimeClock.now()\n }\n deliverRecord(id: RunStreamRecord['id']): boolean {\n if (this.records.has(id)) return false\n this.records.add(id)\n return true\n }\n delivered(cursor: RunCursor | undefined): void {\n if (cursor === undefined || cursor === this.cursor) return\n this.cursor = cursor\n this.records.clear()\n this.failures = 0\n this.lastFailure = undefined\n this.attempts = 0\n this.delay = realtimeTiming.clientReconnectDelay\n }\n schedule(signal: AbortSignal, observer: ConnectionObserver): number | undefined {\n if (signal.aborted) return undefined\n // A healthy idle connection can rotate for hours without producing a new run cursor.\n if (this.openedAt !== undefined && realtimeClock.now() - this.openedAt >= realtimeTiming.heartbeatInterval) {\n this.failures = 0\n this.lastFailure = undefined\n }\n this.openedAt = undefined\n if (++this.failures >= realtimeDefaults.clientMaxReconnectAttempts)\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection repeatedly failed without progress.',\n retryable: false,\n cause: this.lastFailure,\n ...(this.cursor === undefined ? {} : { meta: { cursor: this.cursor } }),\n })\n const scheduled = observer.reconnect(signal, ++this.attempts, this.delay)\n this.delay = Math.min(realtimeTiming.clientMaxReconnectDelay, this.delay * 2)\n return scheduled\n }\n}\n\nasync function* connectionEvents(\n fetcher: typeof fetch,\n url: URL,\n runId: RunId,\n retry: ReconnectState,\n signal: AbortSignal,\n named: boolean,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n // Permanent refresher errors bypass the retryable I/O catch.\n if (!(await retry.readyToken(runId, signal))) return\n yield* readConnection(fetcher, url, retry, signal, named, observer)\n}\n\nasync function* readConnection(\n fetcher: typeof fetch,\n url: URL,\n retry: ReconnectState,\n signal: AbortSignal,\n named: boolean,\n observer: ConnectionObserver,\n): AsyncGenerator<Delivered, void> {\n let body: ReadableStream<Uint8Array> | undefined\n try {\n body = await requestStream(fetcher, url, retry, signal)\n if (body === undefined) return\n retry.open()\n observer.emit({ state: RealtimeConnectionState.Open })\n for await (const event of readSse(body, signal)) yield decodeEvent(event, named)\n } catch (cause) {\n if (observer.failed) throw cause\n if (signal.aborted) return\n if (cause instanceof RunlaneError && cause.retryable) {\n retry.lastFailure = cause\n return\n }\n throw cause\n } finally {\n if (body !== undefined && !body.locked) await body.cancel().catch(() => undefined)\n }\n}\n\nasync function requestStream(\n fetcher: typeof fetch,\n url: URL,\n retry: ReconnectState,\n signal: AbortSignal,\n): Promise<ReadableStream<Uint8Array> | undefined> {\n signal.throwIfAborted()\n const headers = new Headers({ accept: 'text/event-stream' })\n if (retry.accessToken !== undefined) headers.set('authorization', `Bearer ${retry.accessToken}`)\n if (retry.cursor !== undefined) headers.set('last-event-id', retry.cursor)\n const response = await fetchResponse(fetcher, url, headers, signal, retry)\n if (response === undefined) return undefined\n if (response.body === null || !/^text\\/event-stream(?:\\s*;|$)/i.test(response.headers.get('content-type') ?? ''))\n throw wireInvalid()\n return response.body\n}\n\nasync function awaitToken(token: Awaitable<string>, signal: AbortSignal): Promise<string> {\n const aborted = Promise.withResolvers<never>()\n const abort = () => aborted.reject(signal.reason)\n signal.addEventListener('abort', abort, { once: true })\n if (signal.aborted) abort()\n try {\n // The race observes late token rejection even after abort wins.\n return await Promise.race([token, aborted.promise])\n } finally {\n signal.removeEventListener('abort', abort)\n }\n}\n\nasync function fetchResponse(\n fetcher: typeof fetch,\n url: URL,\n headers: Headers,\n signal: AbortSignal,\n retry: ReconnectState,\n): Promise<Response | undefined> {\n let response: Response\n try {\n response = await fetcher(url, { headers, signal, cache: 'no-store', redirect: 'error' })\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime connection was interrupted.',\n retryable: true,\n cause,\n })\n }\n if (response.status >= 500 && response.headers.get('content-type')?.includes('application/json'))\n throw await responseError(response, signal)\n if (response.status === 429 || response.status >= 500) {\n await response.body?.cancel()\n throw new RunlaneError({\n code: ErrorCode.Disconnected,\n message: 'Realtime server is temporarily unavailable.',\n retryable: true,\n })\n }\n if (!response.ok) {\n const error = await responseError(response, signal)\n if (retry.refreshAfterDenial(response.status, error)) return undefined\n throw error\n }\n return response\n}\n\nfunction decodeEvent(event: SseEvent, named: boolean): Delivered {\n const raw = parseWireJson(event.data)\n if (event.event === 'error') {\n const result = runRealtimeErrorSchema.safeParse(raw)\n if (!result.success) throw wireInvalid(result.error)\n const { cursor, ...error } = result.data\n throw new RunlaneError({ ...error, ...(cursor === undefined ? {} : { meta: { cursor } }) })\n }\n if (event.event === 'end' || event.event === 'checkpoint') {\n if (!runRealtimeControlSchema.safeParse(raw).success) throw wireInvalid()\n if (event.event === 'end') return { kind: 'control', terminal: true }\n const cursor = runCursorSchema.safeParse(event.id)\n if (!cursor.success) throw wireInvalid(cursor.error)\n return { kind: 'control', cursor: cursor.data }\n }\n return named ? decodeNamedEvent(event, raw) : decodeSubscriptionEvent(event, raw)\n}\n\nfunction decodeNamedEvent(event: SseEvent, raw: unknown): Delivered {\n const result = runStreamWireSchema.safeParse(raw)\n if (\n !result.success ||\n event.event !== 'stream' ||\n (result.data.cursor !== undefined && result.data.cursor !== event.id)\n )\n throw wireInvalid()\n return { kind: RunReaderKind.Stream, value: result.data.record, cursor: result.data.cursor }\n}\n\nfunction decodeSubscriptionEvent(event: SseEvent, raw: unknown): Delivered {\n const result = runSubscriptionWireSchema.safeParse(raw)\n if (!result.success || String(result.data.type) !== event.event || result.data.cursor !== event.id)\n throw wireInvalid()\n return {\n kind: RunReaderKind.Subscription,\n value: result.data,\n cursor: result.data.cursor,\n terminal: result.data.type === RunSubscriptionEventType.Status && runStatusValues.isTerminal(result.data.status),\n }\n}\n\nasync function responseError(response: Response, signal: AbortSignal): Promise<RunlaneError> {\n if (response.body === null) throw wireInvalid()\n const reader = response.body.getReader()\n const decoder = new TextDecoder('utf-8', { fatal: true })\n let text = ''\n let bytes = 0\n const abort = () => {\n void reader.cancel().catch(() => undefined)\n }\n signal.addEventListener('abort', abort, { once: true })\n try {\n while (!signal.aborted) {\n const chunk = await reader.read()\n if (chunk.done) break\n bytes += chunk.value.byteLength\n if (bytes > realtimeDefaults.maxBufferedBytes) throw wireInvalid()\n text += decoder.decode(chunk.value, { stream: true })\n }\n const raw = parseWireJson(text + decoder.decode())\n const result = realtimeErrorEnvelopeSchema.safeParse(raw)\n if (!result.success) throw wireInvalid(result.error)\n const { cursor, ...error } = result.data.error\n return new RunlaneError({\n ...error,\n ...(cursor === undefined ? {} : { meta: { cursor } }),\n retryable: response.status >= 500 && result.data.error.retryable,\n })\n } finally {\n signal.removeEventListener('abort', abort)\n await reader.cancel().catch(() => undefined)\n reader.releaseLock()\n }\n}\n\nfunction makeUrl(base: URL, runId: RunId, name?: string): URL {\n try {\n const path = name === undefined ? 'events' : `streams/${encodeURIComponent(name)}`\n return new URL(`${base.href.replace(/\\/$/, '')}/runs/${encodeURIComponent(runId)}/${path}`)\n } catch (cause) {\n throw new RunlaneError({\n code: ErrorCode.ValidationFailed,\n message: 'Run id or stream name cannot be encoded in a URL.',\n cause,\n })\n }\n}\n\nexport {\n ErrorCode,\n RunlaneError,\n RunSubscriptionEventType,\n RunStreamRecordType,\n type RunSubscriptionEvent,\n type RunStreamRecord,\n type RunCursor,\n} from '@runlane/contracts/realtime'\n\nexport type {\n RunTypes,\n RunOutput,\n RunMeta,\n RunStreams,\n RunStreamName,\n RunStreamPart,\n} from '@runlane/contracts/realtime'\n"],"mappings":"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"}
package/dist/client.d.cts CHANGED
@@ -17,9 +17,13 @@ export type RunlaneClientReadOptions = Pick<RunSubscribeOptions, 'after' | 'sign
17
17
  readonly accessToken?: string;
18
18
  readonly onConnectionChange?: (change: RealtimeConnectionChange) => void;
19
19
  };
20
+ /** Subscription controls; omit streams to read all streams permitted by the grant. */
21
+ export type RunlaneClientSubscribeOptions = RunlaneClientReadOptions & {
22
+ readonly streams?: false;
23
+ };
20
24
  /** Pull-based readers validate input on the first next(), before effects. Task generics add types only; abort ends normally. */
21
25
  export interface RunlaneClient {
22
- subscribe<TTask = unknown>(runId: RunlaneIdInput, options?: RunlaneClientReadOptions): AsyncGenerator<RunSubscriptionEvent$1<TTask>, void>;
26
+ subscribe<TTask = unknown>(runId: RunlaneIdInput, options?: RunlaneClientSubscribeOptions): AsyncGenerator<RunSubscriptionEvent$1<TTask>, void>;
23
27
  /** Supply TName explicitly for an exact chunk type when TTask declares several streams. */
24
28
  readStream<TTask = unknown, TName extends RunStreamName$1<TTask> = RunStreamName$1<TTask>>(runId: RunlaneIdInput, name: TName, options?: RunlaneClientReadOptions): AsyncGenerator<RunStreamRecord$1<RunStreamPart$1<TTask, TName>>, void>;
25
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.cts","names":["RunSubscriptionEvent","RunStreamName","RunStreamPart","RunStreamRecord"],"sources":["../src/client.ts"],"mappings":";;;iBA6CiB;WACN,OAAO;WACP,QAAQ;;;iBAIF,6BAA6B;WACnC;;WAEA,sBAAsB,SAAS,oBAAoB;WACnD,eAAe,WAAW;;;YAGzB,2BAA2B,KAAK;WACjC;WACA,sBAAsB,QAAQ;;;iBAGxB;EACf,UAAU,iBACR,OAAO,gBACP,UAAU,2BACT,eAAeA,uBAAqB;;EAEvC,WAAW,iBAAiB,cAAcC,gBAAc,SAASA,gBAAc,QAC7E,OAAO,gBACP,MAAM,OACN,UAAU,2BACT,eAAeE,kBAAgBD,gBAAc,OAAO;;;wBA8CzC,oBAAoB,SAAS,uBAAuB"}
1
+ {"version":3,"file":"client.d.cts","names":["RunSubscriptionEvent","RunStreamName","RunStreamPart","RunStreamRecord"],"sources":["../src/client.ts"],"mappings":";;;iBA6CiB;WACN,OAAO;WACP,QAAQ;;;iBAIF,6BAA6B;WACnC;;WAEA,sBAAsB,SAAS,oBAAoB;WACnD,eAAe,WAAW;;;YAGzB,2BAA2B,KAAK;WACjC;WACA,sBAAsB,QAAQ;;;YAG7B,gCAAgC;WACjC;;;iBAGM;EACf,UAAU,iBACR,OAAO,gBACP,UAAU,gCACT,eAAeA,uBAAqB;;EAEvC,WAAW,iBAAiB,cAAcC,gBAAc,SAASA,gBAAc,QAC7E,OAAO,gBACP,MAAM,OACN,UAAU,2BACT,eAAeE,kBAAgBD,gBAAc,OAAO;;;wBAmDzC,oBAAoB,SAAS,uBAAuB"}
package/dist/client.d.mts CHANGED
@@ -17,9 +17,13 @@ export type RunlaneClientReadOptions = Pick<RunSubscribeOptions, 'after' | 'sign
17
17
  readonly accessToken?: string;
18
18
  readonly onConnectionChange?: (change: RealtimeConnectionChange) => void;
19
19
  };
20
+ /** Subscription controls; omit streams to read all streams permitted by the grant. */
21
+ export type RunlaneClientSubscribeOptions = RunlaneClientReadOptions & {
22
+ readonly streams?: false;
23
+ };
20
24
  /** Pull-based readers validate input on the first next(), before effects. Task generics add types only; abort ends normally. */
21
25
  export interface RunlaneClient {
22
- subscribe<TTask = unknown>(runId: RunlaneIdInput, options?: RunlaneClientReadOptions): AsyncGenerator<RunSubscriptionEvent$1<TTask>, void>;
26
+ subscribe<TTask = unknown>(runId: RunlaneIdInput, options?: RunlaneClientSubscribeOptions): AsyncGenerator<RunSubscriptionEvent$1<TTask>, void>;
23
27
  /** Supply TName explicitly for an exact chunk type when TTask declares several streams. */
24
28
  readStream<TTask = unknown, TName extends RunStreamName$1<TTask> = RunStreamName$1<TTask>>(runId: RunlaneIdInput, name: TName, options?: RunlaneClientReadOptions): AsyncGenerator<RunStreamRecord$1<RunStreamPart$1<TTask, TName>>, void>;
25
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.mts","names":["RunSubscriptionEvent","RunStreamName","RunStreamPart","RunStreamRecord"],"sources":["../src/client.ts"],"mappings":";;;iBA6CiB;WACN,OAAO;WACP,QAAQ;;;iBAIF,6BAA6B;WACnC;;WAEA,sBAAsB,SAAS,oBAAoB;WACnD,eAAe,WAAW;;;YAGzB,2BAA2B,KAAK;WACjC;WACA,sBAAsB,QAAQ;;;iBAGxB;EACf,UAAU,iBACR,OAAO,gBACP,UAAU,2BACT,eAAeA,uBAAqB;;EAEvC,WAAW,iBAAiB,cAAcC,gBAAc,SAASA,gBAAc,QAC7E,OAAO,gBACP,MAAM,OACN,UAAU,2BACT,eAAeE,kBAAgBD,gBAAc,OAAO;;;wBA8CzC,oBAAoB,SAAS,uBAAuB"}
1
+ {"version":3,"file":"client.d.mts","names":["RunSubscriptionEvent","RunStreamName","RunStreamPart","RunStreamRecord"],"sources":["../src/client.ts"],"mappings":";;;iBA6CiB;WACN,OAAO;WACP,QAAQ;;;iBAIF,6BAA6B;WACnC;;WAEA,sBAAsB,SAAS,oBAAoB;WACnD,eAAe,WAAW;;;YAGzB,2BAA2B,KAAK;WACjC;WACA,sBAAsB,QAAQ;;;YAG7B,gCAAgC;WACjC;;;iBAGM;EACf,UAAU,iBACR,OAAO,gBACP,UAAU,gCACT,eAAeA,uBAAqB;;EAEvC,WAAW,iBAAiB,cAAcC,gBAAc,SAASA,gBAAc,QAC7E,OAAO,gBACP,MAAM,OACN,UAAU,2BACT,eAAeE,kBAAgBD,gBAAc,OAAO;;;wBAmDzC,oBAAoB,SAAS,uBAAuB"}
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as wireInvalid, n as realtimeTiming, r as invalidOptions, t as realtimeClock } from "./time-sHQYGDPD.mjs";
1
+ import { a as invalidOptions, i as realtimeTiming, n as streamSelectionQuery, o as wireInvalid, r as realtimeClock, t as parseWireJson } from "./wire-BEevjo-K.mjs";
2
2
  import { ErrorCode, ErrorCode as ErrorCode$1, RealtimeConnectionCloseReason, RealtimeConnectionState, RunReaderKind, RunStreamRecordType, RunSubscriptionEventType, RunSubscriptionEventType as RunSubscriptionEventType$1, RunlaneError, RunlaneError as RunlaneError$1, RunlaneMetricAttribute, RunlaneMetricName, createRunlaneIdSchema, realtimeDefaults, recordRunlaneTelemetryMetric, runCursorSchema, runRealtimeControlSchema, runRealtimeErrorSchema, runStatusValues, runStreamNameSchema, runStreamWireSchema, runSubscriptionWireSchema } from "@runlane/contracts/realtime";
3
3
  import { createFunctionSchema, createUrlSchema, getDownwardJitteredDelayMs, objectSurfaceSchema, waitForAbortableTimeout } from "@runlane/utilities/browser";
4
4
  import * as z$1 from "zod";
@@ -51,7 +51,7 @@ var ConnectionObserver = class {
51
51
  }
52
52
  };
53
53
  // src/sse.ts
54
- const encoder$1 = new TextEncoder();
54
+ const encoder = new TextEncoder();
55
55
  /** Incremental UTF-8 SSE parser; incomplete trailing events are never dispatched. */
56
56
  async function* readSse(body, signal) {
57
57
  const reader = body.getReader();
@@ -114,7 +114,7 @@ var FrameByteBudget = class {
114
114
  this.resetAfterCr = false;
115
115
  }
116
116
  const point = char.codePointAt(0) ?? 0;
117
- this.retained += point < 128 ? 1 : encoder$1.encode(char).byteLength;
117
+ this.retained += point < 128 ? 1 : encoder.encode(char).byteLength;
118
118
  if (this.retained > realtimeDefaults.maxEventBytes) throw wireInvalid();
119
119
  if (this.skipLf && char === "\n") {
120
120
  this.skipLf = false;
@@ -153,17 +153,6 @@ function decodeUtf8(decoder, bytes) {
153
153
  throw wireInvalid(cause);
154
154
  }
155
155
  }
156
- // src/wire.ts
157
- const encoder = new TextEncoder();
158
- /** Parses JSON within the serialized UTF-8 event bound. Storage owns application value validation. */
159
- function parseWireJson(text) {
160
- try {
161
- if (encoder.encode(text).byteLength > realtimeDefaults.maxEventBytes) throw wireInvalid();
162
- return JSON.parse(text);
163
- } catch (cause) {
164
- throw wireInvalid(cause);
165
- }
166
- }
167
156
  // src/client.ts
168
157
  const realtimeErrorEnvelopeSchema = z$1.object({ error: runRealtimeErrorSchema });
169
158
  const clientOptionsSchema = z$1.strictObject({
@@ -180,7 +169,8 @@ const readerFields = {
180
169
  const readerRequestSchema = z$1.discriminatedUnion("kind", [z$1.object({
181
170
  ...readerFields,
182
171
  kind: z$1.literal(RunReaderKind.Subscription),
183
- name: z$1.undefined()
172
+ name: z$1.undefined(),
173
+ streams: z$1.literal(false).optional()
184
174
  }), z$1.object({
185
175
  ...readerFields,
186
176
  kind: z$1.literal(RunReaderKind.Stream),
@@ -208,15 +198,17 @@ async function* connect(options, fetcher, base, runId, name, kind, input = {}) {
208
198
  kind,
209
199
  runId,
210
200
  name,
211
- after: input.after
201
+ after: input.after,
202
+ streams: input.streams
212
203
  });
213
204
  if (!checked.success) throw new RunlaneError$1({
214
205
  code: checked.error.issues[0]?.path[0] === "after" ? ErrorCode$1.RunCursorInvalid : ErrorCode$1.ValidationFailed,
215
- message: "Run id, stream name, or after cursor is invalid.",
206
+ message: "Run id, stream name, stream selection, or after cursor is invalid.",
216
207
  cause: checked.error
217
208
  });
218
209
  const request = checked.data;
219
210
  const url = makeUrl(base, request.runId, request.name);
211
+ if (request.kind === RunReaderKind.Subscription && request.streams === false) url.searchParams.set(streamSelectionQuery.name, streamSelectionQuery.none);
220
212
  const signal = input.signal ?? new AbortController().signal;
221
213
  const observer = new ConnectionObserver(input.onConnectionChange);
222
214
  let failure;