Skip to content

Commit d43ef3f

Browse files
committed
feat(client): add support for server-sent events
1 parent 649349a commit d43ef3f

File tree

907 files changed

+88657
-21932
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

907 files changed

+88657
-21932
lines changed

.changeset/brown-pandas-stare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@hey-api/openapi-ts': minor
3+
---
4+
5+
feat(client): add support for server-sent events (SSE)

docs/openapi-ts/migrating.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@ description: Migrating to @hey-api/openapi-ts.
77

88
While we try to avoid breaking changes, sometimes it's unavoidable in order to offer you the latest features. This page lists changes that require updates to your code. If you run into a problem with migration, please [open an issue](https://github.com/hey-api/openapi-ts/issues).
99

10+
## v0.81.0
11+
12+
### Server-Sent Events (SSE)
13+
14+
This release adds support for server-sent events (SSE). Instead of treating `text/event-stream` content types as regular HTTP methods, we now generate SSE streams. In practice, you will want to update your affected endpoints to process streamed events.
15+
16+
::: code-group
17+
18+
```js [before]
19+
const { data } = await foo();
20+
console.log(data.type);
21+
```
22+
23+
```js [after]
24+
const { stream } = await foo();
25+
for await (const event of stream) {
26+
console.log(event.type);
27+
}
28+
```
29+
30+
:::
31+
1032
## v0.80.0
1133

1234
### Added Zod 4 and Zod Mini

packages/openapi-ts-tests/main/test/3.1.x.test.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,81 @@ describe(`OpenAPI ${version}`, () => {
807807
description:
808808
'generates validator schemas for all integer format combinations (number/integer/string types with int8, int16, int32, int64, uint8, uint16, uint32, uint64 formats)',
809809
},
810+
{
811+
config: createConfig({
812+
input: 'opencode.yaml',
813+
output: 'sse-angular',
814+
parser: {
815+
filters: {
816+
operations: {
817+
include: ['GET /event'],
818+
},
819+
},
820+
},
821+
plugins: ['@hey-api/client-angular', '@hey-api/sdk'],
822+
}),
823+
description: 'client with SSE (Angular)',
824+
},
825+
{
826+
config: createConfig({
827+
input: 'opencode.yaml',
828+
output: 'sse-axios',
829+
parser: {
830+
filters: {
831+
operations: {
832+
include: ['GET /event'],
833+
},
834+
},
835+
},
836+
plugins: ['@hey-api/client-axios', '@hey-api/sdk'],
837+
}),
838+
description: 'client with SSE (Axios)',
839+
},
840+
{
841+
config: createConfig({
842+
input: 'opencode.yaml',
843+
output: 'sse-fetch',
844+
parser: {
845+
filters: {
846+
operations: {
847+
include: ['GET /event'],
848+
},
849+
},
850+
},
851+
plugins: ['@hey-api/client-fetch', '@hey-api/sdk'],
852+
}),
853+
description: 'client with SSE (Fetch)',
854+
},
855+
{
856+
config: createConfig({
857+
input: 'opencode.yaml',
858+
output: 'sse-next',
859+
parser: {
860+
filters: {
861+
operations: {
862+
include: ['GET /event'],
863+
},
864+
},
865+
},
866+
plugins: ['@hey-api/client-next', '@hey-api/sdk'],
867+
}),
868+
description: 'client with SSE (Next.js)',
869+
},
870+
{
871+
config: createConfig({
872+
input: 'opencode.yaml',
873+
output: 'sse-nuxt',
874+
parser: {
875+
filters: {
876+
operations: {
877+
include: ['GET /event'],
878+
},
879+
},
880+
},
881+
plugins: ['@hey-api/client-nuxt', '@hey-api/sdk'],
882+
}),
883+
description: 'client with SSE (Nuxt)',
884+
},
810885
];
811886

812887
it.each(scenarios)('$description', async ({ config }) => {

packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/body-response-text-plain/client/client.gen.ts

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
// This file is auto-generated by @hey-api/openapi-ts
22

3-
import type { Client, Config, ResolvedRequestOptions } from './types.gen';
3+
import { createSseClient } from '../core/serverSentEvents.gen';
4+
import type {
5+
Client,
6+
Config,
7+
RequestOptions,
8+
ResolvedRequestOptions,
9+
} from './types.gen';
410
import {
511
buildUrl,
612
createConfig,
@@ -33,7 +39,7 @@ export const createClient = (config: Config = {}): Client => {
3339
ResolvedRequestOptions
3440
>();
3541

36-
const request: Client['request'] = async (options) => {
42+
const beforeRequest = async (options: RequestOptions) => {
3743
const opts = {
3844
..._config,
3945
...options,
@@ -63,6 +69,13 @@ export const createClient = (config: Config = {}): Client => {
6369
}
6470

6571
const url = buildUrl(opts);
72+
73+
return { opts, url };
74+
};
75+
76+
const request: Client['request'] = async (options) => {
77+
// @ts-expect-error
78+
const { opts, url } = await beforeRequest(options);
6679
const requestInit: ReqInit = {
6780
redirect: 'follow',
6881
...opts,
@@ -180,20 +193,35 @@ export const createClient = (config: Config = {}): Client => {
180193
};
181194
};
182195

196+
const makeMethod = (method: Required<Config>['method']) => {
197+
const fn = (options: RequestOptions) => request({ ...options, method });
198+
fn.sse = async (options: RequestOptions) => {
199+
const { opts, url } = await beforeRequest(options);
200+
return createSseClient({
201+
...opts,
202+
body: opts.body as BodyInit | null | undefined,
203+
headers: opts.headers as unknown as Record<string, string>,
204+
method,
205+
url,
206+
});
207+
};
208+
return fn;
209+
};
210+
183211
return {
184212
buildUrl,
185-
connect: (options) => request({ ...options, method: 'CONNECT' }),
186-
delete: (options) => request({ ...options, method: 'DELETE' }),
187-
get: (options) => request({ ...options, method: 'GET' }),
213+
connect: makeMethod('CONNECT'),
214+
delete: makeMethod('DELETE'),
215+
get: makeMethod('GET'),
188216
getConfig,
189-
head: (options) => request({ ...options, method: 'HEAD' }),
217+
head: makeMethod('HEAD'),
190218
interceptors,
191-
options: (options) => request({ ...options, method: 'OPTIONS' }),
192-
patch: (options) => request({ ...options, method: 'PATCH' }),
193-
post: (options) => request({ ...options, method: 'POST' }),
194-
put: (options) => request({ ...options, method: 'PUT' }),
219+
options: makeMethod('OPTIONS'),
220+
patch: makeMethod('PATCH'),
221+
post: makeMethod('POST'),
222+
put: makeMethod('PUT'),
195223
request,
196224
setConfig,
197-
trace: (options) => request({ ...options, method: 'TRACE' }),
198-
};
225+
trace: makeMethod('TRACE'),
226+
} as Client;
199227
};

packages/openapi-ts-tests/main/test/__snapshots__/2.0.x/body-response-text-plain/client/types.gen.ts

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
// This file is auto-generated by @hey-api/openapi-ts
22

33
import type { Auth } from '../core/auth.gen';
4+
import type {
5+
ServerSentEventsOptions,
6+
ServerSentEventsResult,
7+
} from '../core/serverSentEvents.gen';
48
import type {
59
Client as CoreClient,
610
Config as CoreConfig,
@@ -61,13 +65,22 @@ export interface Config<T extends ClientOptions = ClientOptions>
6165
}
6266

6367
export interface RequestOptions<
68+
TData = unknown,
6469
TResponseStyle extends ResponseStyle = 'fields',
6570
ThrowOnError extends boolean = boolean,
6671
Url extends string = string,
6772
> extends Config<{
68-
responseStyle: TResponseStyle;
69-
throwOnError: ThrowOnError;
70-
}> {
73+
responseStyle: TResponseStyle;
74+
throwOnError: ThrowOnError;
75+
}>,
76+
Pick<
77+
ServerSentEventsOptions<TData>,
78+
| 'onSseError'
79+
| 'onSseEvent'
80+
| 'sseDefaultRetryDelay'
81+
| 'sseMaxRetryAttempts'
82+
| 'sseMaxRetryDelay'
83+
> {
7184
/**
7285
* Any body that you want to add to your request.
7386
*
@@ -87,7 +100,7 @@ export interface ResolvedRequestOptions<
87100
TResponseStyle extends ResponseStyle = 'fields',
88101
ThrowOnError extends boolean = boolean,
89102
Url extends string = string,
90-
> extends RequestOptions<TResponseStyle, ThrowOnError, Url> {
103+
> extends RequestOptions<unknown, TResponseStyle, ThrowOnError, Url> {
91104
serializedBody?: string;
92105
}
93106

@@ -142,23 +155,39 @@ export interface ClientOptions {
142155
throwOnError?: boolean;
143156
}
144157

145-
type MethodFn = <
158+
type MethodFnBase = <
146159
TData = unknown,
147160
TError = unknown,
148161
ThrowOnError extends boolean = false,
149162
TResponseStyle extends ResponseStyle = 'fields',
150163
>(
151-
options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'>,
164+
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'>,
152165
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
153166

167+
type MethodFnServerSentEvents = <
168+
TData = unknown,
169+
TError = unknown,
170+
ThrowOnError extends boolean = false,
171+
TResponseStyle extends ResponseStyle = 'fields',
172+
>(
173+
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'>,
174+
) => Promise<ServerSentEventsResult<TData, TError>>;
175+
176+
type MethodFn = MethodFnBase & {
177+
sse: MethodFnServerSentEvents;
178+
};
179+
154180
type RequestFn = <
155181
TData = unknown,
156182
TError = unknown,
157183
ThrowOnError extends boolean = false,
158184
TResponseStyle extends ResponseStyle = 'fields',
159185
>(
160-
options: Omit<RequestOptions<TResponseStyle, ThrowOnError>, 'method'> &
161-
Pick<Required<RequestOptions<TResponseStyle, ThrowOnError>>, 'method'>,
186+
options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, 'method'> &
187+
Pick<
188+
Required<RequestOptions<TData, TResponseStyle, ThrowOnError>>,
189+
'method'
190+
>,
162191
) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
163192

164193
type BuildUrlFn = <
@@ -201,9 +230,10 @@ type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
201230
export type Options<
202231
TData extends TDataShape = TDataShape,
203232
ThrowOnError extends boolean = boolean,
233+
TResponse = unknown,
204234
TResponseStyle extends ResponseStyle = 'fields',
205235
> = OmitKeys<
206-
RequestOptions<TResponseStyle, ThrowOnError>,
236+
RequestOptions<TResponse, TResponseStyle, ThrowOnError>,
207237
'body' | 'path' | 'query' | 'url'
208238
> &
209239
Omit<TData, 'url'>;
@@ -215,18 +245,22 @@ export type OptionsLegacyParser<
215245
> = TData extends { body?: any }
216246
? TData extends { headers?: any }
217247
? OmitKeys<
218-
RequestOptions<TResponseStyle, ThrowOnError>,
248+
RequestOptions<unknown, TResponseStyle, ThrowOnError>,
219249
'body' | 'headers' | 'url'
220250
> &
221251
TData
222-
: OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'body' | 'url'> &
252+
: OmitKeys<
253+
RequestOptions<unknown, TResponseStyle, ThrowOnError>,
254+
'body' | 'url'
255+
> &
223256
TData &
224-
Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'headers'>
257+
Pick<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'headers'>
225258
: TData extends { headers?: any }
226259
? OmitKeys<
227-
RequestOptions<TResponseStyle, ThrowOnError>,
260+
RequestOptions<unknown, TResponseStyle, ThrowOnError>,
228261
'headers' | 'url'
229262
> &
230263
TData &
231-
Pick<RequestOptions<TResponseStyle, ThrowOnError>, 'body'>
232-
: OmitKeys<RequestOptions<TResponseStyle, ThrowOnError>, 'url'> & TData;
264+
Pick<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'body'>
265+
: OmitKeys<RequestOptions<unknown, TResponseStyle, ThrowOnError>, 'url'> &
266+
TData;

0 commit comments

Comments
 (0)