diff --git a/generators/typescript/sdk/CHANGELOG.md b/generators/typescript/sdk/CHANGELOG.md index 6d384ad81cb..916c782bc83 100644 --- a/generators/typescript/sdk/CHANGELOG.md +++ b/generators/typescript/sdk/CHANGELOG.md @@ -5,15 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.15.0-rc1] - 2024-04-22 + +- Fix: Minor fixes to SSE processing. In particular, stream terminal characters are now + respected like `[DONE]` and JSON parsed data is sent to the deserialize function. + ## [0.15.0-rc0] - 2024-04-19 -- Feature: Bump to v38 of IR and support server-sent events where the events are sent - with a `data: ` prefix and terminated with a new line. +- Feature: Bump to v38 of IR and support server-sent events where the events are sent + with a `data: ` prefix and terminated with a new line. ## [0.14.1-rc5] - 2024-04-17 -- Fix: Code snippets are generated for file upload endpoints using `fs.readStream`. Previously, - generation for these endpoints was being skipped. +- Fix: Code snippets are generated for file upload endpoints using `fs.readStream`. Previously, + generation for these endpoints was being skipped. - Fix: If integration tests are not enabled, simple jest tests with a `yarn test` script will be created. diff --git a/generators/typescript/sdk/VERSION b/generators/typescript/sdk/VERSION index 2d5bf8a9b93..be8193a500e 100644 --- a/generators/typescript/sdk/VERSION +++ b/generators/typescript/sdk/VERSION @@ -1 +1 @@ -0.15.0-rc0 \ No newline at end of file +0.15.0-rc1 \ No newline at end of file diff --git a/generators/typescript/sdk/client-class-generator/src/endpoints/default/endpoint-response/GeneratedThrowingEndpointResponse.ts b/generators/typescript/sdk/client-class-generator/src/endpoints/default/endpoint-response/GeneratedThrowingEndpointResponse.ts index a01393e5ccb..b3f2f898220 100644 --- a/generators/typescript/sdk/client-class-generator/src/endpoints/default/endpoint-response/GeneratedThrowingEndpointResponse.ts +++ b/generators/typescript/sdk/client-class-generator/src/endpoints/default/endpoint-response/GeneratedThrowingEndpointResponse.ts @@ -151,7 +151,10 @@ export class GeneratedThrowingEndpointResponse implements GeneratedEndpointRespo const eventShape = this.response.value._visit< StreamingFetcher.MessageEventShape | StreamingFetcher.SSEEventShape >({ - sse: () => ({ type: "sse" }), + sse: (sse) => ({ + type: "sse", + streamTerminator: ts.factory.createStringLiteral(sse.terminator ?? "[DONE]") + }), json: (json) => ({ type: "json", messageTerminator: ts.factory.createStringLiteral(json.terminator ?? "\n") diff --git a/generators/typescript/utils/commons/src/core-utilities/stream-utils/StreamUtilsImpl.ts b/generators/typescript/utils/commons/src/core-utilities/stream-utils/StreamUtilsImpl.ts index bbcc1818ef7..c95def315df 100644 --- a/generators/typescript/utils/commons/src/core-utilities/stream-utils/StreamUtilsImpl.ts +++ b/generators/typescript/utils/commons/src/core-utilities/stream-utils/StreamUtilsImpl.ts @@ -37,6 +37,14 @@ export class StreamingUtilsImpl extends CoreUtility implements StreamUtils { ts.factory.createStringLiteral("sse") ) ); + if (eventShape.streamTerminator != null) { + eventShapeProperties.push( + ts.factory.createPropertyAssignment( + ts.factory.createIdentifier("streamTerminator"), + eventShape.streamTerminator ?? ts.factory.createStringLiteral("\n") + ) + ); + } } else if (eventShape.type === "json") { eventShapeProperties.push( ts.factory.createPropertyAssignment( diff --git a/generators/typescript/utils/core-utilities/fetcher/src/stream/Stream.ts b/generators/typescript/utils/core-utilities/fetcher/src/stream/Stream.ts index 08266c3d312..f248e47de8c 100644 --- a/generators/typescript/utils/core-utilities/fetcher/src/stream/Stream.ts +++ b/generators/typescript/utils/core-utilities/fetcher/src/stream/Stream.ts @@ -35,6 +35,7 @@ export class Stream implements AsyncIterable { */ private prefix: string | undefined; private messageTerminator: string; + private streamTerminator: string | undefined; constructor({ stream, parse, eventShape }: Stream.Args & { parse: (val: unknown) => Promise }) { this.stream = stream; @@ -42,6 +43,7 @@ export class Stream implements AsyncIterable { if (eventShape.type === "sse") { this.prefix = DATA_PREFIX; this.messageTerminator = "\n"; + this.streamTerminator = eventShape.streamTerminator; } else { this.messageTerminator = eventShape.messageTerminator; } @@ -66,10 +68,13 @@ export class Stream implements AsyncIterable { prefixSeen = true; buf = buf.slice(prefixIndex + this.prefix.length); } - // Yield message from the prefix to the terminator const line = buf.slice(0, terminatorIndex).trimEnd(); - console.log(line); - const message = await this.parse(line); + // If the stream terminator is present, return + if (this.streamTerminator != null && line.includes(this.streamTerminator)) { + return; + } + // Otherwise, yield message from the prefix to the terminator + const message = await this.parse(JSON.parse(line)); yield message; buf = buf.slice(terminatorIndex + 1); prefixSeen = false; @@ -129,6 +134,6 @@ export function readableStreamAsyncIterable(stream: any): AsyncIterableIterat }, [Symbol.asyncIterator]() { return this; - } + }, }; } diff --git a/seed/ts-sdk/server-sent-events/snippet-templates.json b/seed/ts-sdk/server-sent-events/snippet-templates.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/seed/ts-sdk/server-sent-events/src/api/resources/completions/client/Client.ts b/seed/ts-sdk/server-sent-events/src/api/resources/completions/client/Client.ts index 1ce48dfb0cf..312620d7448 100644 --- a/seed/ts-sdk/server-sent-events/src/api/resources/completions/client/Client.ts +++ b/seed/ts-sdk/server-sent-events/src/api/resources/completions/client/Client.ts @@ -56,6 +56,7 @@ export class Completions { }, eventShape: { type: "sse", + streamTerminator: "[[DONE]]", }, }); } diff --git a/seed/ts-sdk/server-sent-events/src/core/streaming-fetcher/Stream.ts b/seed/ts-sdk/server-sent-events/src/core/streaming-fetcher/Stream.ts index fa1952582d4..f248e47de8c 100644 --- a/seed/ts-sdk/server-sent-events/src/core/streaming-fetcher/Stream.ts +++ b/seed/ts-sdk/server-sent-events/src/core/streaming-fetcher/Stream.ts @@ -35,6 +35,7 @@ export class Stream implements AsyncIterable { */ private prefix: string | undefined; private messageTerminator: string; + private streamTerminator: string | undefined; constructor({ stream, parse, eventShape }: Stream.Args & { parse: (val: unknown) => Promise }) { this.stream = stream; @@ -42,6 +43,7 @@ export class Stream implements AsyncIterable { if (eventShape.type === "sse") { this.prefix = DATA_PREFIX; this.messageTerminator = "\n"; + this.streamTerminator = eventShape.streamTerminator; } else { this.messageTerminator = eventShape.messageTerminator; } @@ -66,10 +68,13 @@ export class Stream implements AsyncIterable { prefixSeen = true; buf = buf.slice(prefixIndex + this.prefix.length); } - // Yield message from the prefix to the terminator const line = buf.slice(0, terminatorIndex).trimEnd(); - console.log(line); - const message = await this.parse(line); + // If the stream terminator is present, return + if (this.streamTerminator != null && line.includes(this.streamTerminator)) { + return; + } + // Otherwise, yield message from the prefix to the terminator + const message = await this.parse(JSON.parse(line)); yield message; buf = buf.slice(terminatorIndex + 1); prefixSeen = false;