diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index a72de61d..fc92d2db 100755 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -4,7 +4,7 @@ management: docChecksum: 34d22936f2456c2c461abdfc773e3fc4 docVersion: 0.0.3 speakeasyVersion: internal - generationVersion: 2.233.2 + generationVersion: 2.234.3 releaseVersion: 0.4.0 configChecksum: 857d3a3d03c912d0f09faf0342203722 repoURL: https://github.com/LukeHagar/plexjs.git @@ -43,6 +43,7 @@ generatedFiles: - src/lib/base64.ts - src/lib/config.ts - src/lib/encodings.ts + - src/lib/event-streams.ts - src/lib/http.ts - src/lib/retries.ts - src/lib/sdks.ts diff --git a/RELEASES.md b/RELEASES.md index d7c0e9ff..7fb18ed8 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -78,4 +78,14 @@ Based on: ### Generated - [typescript v0.4.0] . ### Releases +- [NPM v0.4.0] https://www.npmjs.com/package/@lukehagar/plexjs/v/0.4.0 - . + +## 2024-01-17 00:27:57 +### Changes +Based on: +- OpenAPI Doc 0.0.3 +- Speakeasy CLI 1.142.1 (2.234.3) https://github.com/speakeasy-api/speakeasy +### Generated +- [typescript v0.4.0] . +### Releases - [NPM v0.4.0] https://www.npmjs.com/package/@lukehagar/plexjs/v/0.4.0 - . \ No newline at end of file diff --git a/src/lib/config.ts b/src/lib/config.ts index 791f8d57..3efa14f8 100644 --- a/src/lib/config.ts +++ b/src/lib/config.ts @@ -80,6 +80,6 @@ export const SDK_METADATA = Object.freeze({ language: "typescript", openapiDocVersion: "0.0.3", sdkVersion: "0.4.0", - genVersion: "2.233.2", - userAgent: "speakeasy-sdk/typescript 0.4.0 2.233.2 0.0.3 @lukehagar/plexjs", + genVersion: "2.234.3", + userAgent: "speakeasy-sdk/typescript 0.4.0 2.234.3 0.0.3 @lukehagar/plexjs", }); diff --git a/src/lib/event-streams.ts b/src/lib/event-streams.ts new file mode 100644 index 00000000..02ca47e8 --- /dev/null +++ b/src/lib/event-streams.ts @@ -0,0 +1,192 @@ +/* + * Code generated by Speakeasy (https://speakeasyapi.dev). DO NOT EDIT. + */ + +export type ServerEvent = { + data?: T | undefined; + event?: string | undefined; + retry?: number | undefined; + id?: string | undefined; +}; +const LF = 0x0a; +const CR = 0x0d; +const NEWLINE_CHARS = new Set([LF, CR]); +const MESSAGE_BOUNDARIES = [ + new Uint8Array([CR, LF, CR, LF]), + new Uint8Array([CR, CR]), + new Uint8Array([LF, LF]), +]; + +export class EventStream> { + private readonly stream: ReadableStream; + private readonly decoder: (rawEvent: ServerEvent) => Event; + + constructor(init: { + stream: ReadableStream; + decoder: (rawEvent: ServerEvent) => Event; + }) { + this.stream = init.stream; + this.decoder = init.decoder; + } + + async *[Symbol.asyncIterator]() { + const reader = this.stream.getReader(); + let buffer = new Uint8Array([]); + let position = 0; + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) { + break; + } + + const newBuffer = new Uint8Array(buffer.length + value.length); + newBuffer.set(buffer); + newBuffer.set(value, buffer.length); + buffer = newBuffer; + + for (let i = position; i < buffer.length; i++) { + const boundary = findBoundary(buffer, i); + if (boundary == null) { + continue; + } + + const chunk = buffer.slice(position, i); + position = i + boundary.length; + const event = parseEvent(chunk, this.decoder); + if (event != null) { + yield event; + } + } + + if (position > 0) { + buffer = buffer.slice(position); + position = 0; + } + } + + if (buffer.length > 0) { + const event = parseEvent(buffer, this.decoder); + if (event != null) { + yield event; + } + } + } finally { + reader.releaseLock(); + } + } +} + +function findBoundary(buffer: Uint8Array, start: number): Uint8Array | null { + const char1 = buffer[start]; + const char2 = buffer[start + 1]; + + // Don't bother checking if the first two characters are not new line + // characters. + if ( + char1 == null || + char2 == null || + !NEWLINE_CHARS.has(char1) || + !NEWLINE_CHARS.has(char2) + ) { + return null; + } + + for (const s of MESSAGE_BOUNDARIES) { + const seq = peekSequence(start, buffer, s); + if (seq != null) { + return seq; + } + } + + return null; +} + +function peekSequence( + position: number, + buffer: Uint8Array, + sequence: Uint8Array, +): Uint8Array | null { + if (sequence.length > buffer.length - position) { + return null; + } + + for (let i = 0; i < sequence.length; i++) { + if (buffer[position + i] !== sequence[i]) { + return null; + } + } + + return sequence; +} + +function parseEvent>( + chunk: Uint8Array, + decoder: (rawEvent: ServerEvent) => Event, +) { + if (!chunk.length) { + return null; + } + + const td = new TextDecoder(); + const raw = td.decode(chunk); + const lines = raw.split(/\r?\n|\r/g); + let publish = false; + const rawEvent: ServerEvent = {}; + + for (const line of lines) { + if (!line) { + continue; + } + + const delim = line.indexOf(":"); + // Lines starting with a colon are ignored. + if (delim === 0) { + continue; + } + + const field = delim > 0 ? line.substring(0, delim) : ""; + let value = delim > 0 ? line.substring(delim + 1) : ""; + if (value.charAt(0) === " ") { + value = value.substring(1); + } + + switch (field) { + case "event": { + publish = true; + rawEvent.event = value; + break; + } + case "data": { + publish = true; + rawEvent.data ??= ""; + rawEvent.data += value + "\n"; + break; + } + case "id": { + publish = true; + rawEvent.id = value; + break; + } + case "retry": { + const r = parseInt(value, 10); + if (!Number.isNaN(r)) { + publish = true; + rawEvent.retry = r; + } + break; + } + } + } + + if (!publish) { + return null; + } + + if (rawEvent.data != null) { + rawEvent.data = rawEvent.data.slice(0, -1); + } + + return decoder(rawEvent); +}