Skip to content

Commit b044b59

Browse files
authored
feat: set max connections to 100, allow integrators to configure Fetch API (#98)
1 parent eb1f9a8 commit b044b59

File tree

10 files changed

+435
-375
lines changed

10 files changed

+435
-375
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"@types/jsonwebtoken": "^9.0.3",
7474
"@types/node": "^20.11.24",
7575
"jsonwebtoken": "^9.0.2",
76+
"undici": "^5.29.0",
7677
"uuid": "^9.0.1"
7778
},
7879
"peerDependencies": {

src/BaseApi.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ import { v4 as uuidv4 } from 'uuid';
22
import { ApiConfig, RequestMetadata, StreamError } from './types';
33
import { APIError } from './gen/models';
44
import { getRateLimitFromResponseHeader } from './utils/rate-limit';
5+
import { Agent } from 'undici';
56

67
export class BaseApi {
7-
constructor(protected readonly apiConfig: ApiConfig) {}
8+
private readonly dispatcher: Agent;
9+
10+
constructor(protected readonly apiConfig: ApiConfig) {
11+
this.dispatcher = this.apiConfig.agent;
12+
}
813

914
protected sendRequest = async <T>(
1015
method: string,
@@ -21,6 +26,7 @@ export class BaseApi {
2126
url = url.replace(`{${paramName}}`, pathParams[paramName]);
2227
});
2328
}
29+
2430
url += `?${encodedParams}`;
2531
const clientRequestId = uuidv4();
2632
const headers = {
@@ -40,6 +46,8 @@ export class BaseApi {
4046
method,
4147
body: JSON.stringify(body),
4248
headers,
49+
/** @ts-expect-error we get types from DOM here, but we should use node types */
50+
dispatcher: this.dispatcher,
4351
});
4452

4553
const responseHeaders = response.headers;

src/StreamClient.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,15 @@ import { StreamChatClient } from './StreamChatClient';
66
import { CallTokenPayload, UserTokenPayload } from './types';
77
import { QueryBannedUsersPayload, UserRequest } from './gen/models';
88
import { StreamModerationClient } from './StreamModerationClient';
9+
import { Agent } from 'undici';
910

1011
export interface StreamClientOptions {
1112
timeout?: number;
1213
basePath?: string;
14+
/** The max number of clients to create. `null` if no limit. Default is 100. Has no effect if `agent` is provided. */
15+
maxConnections?: number | null;
16+
/** The [HTTP Agent](https://undici.nodejs.org/#/docs/api/Agent.md) to use. */
17+
agent?: Agent;
1318
}
1419

1520
export class StreamClient extends CommonApi {
@@ -19,6 +24,7 @@ export class StreamClient extends CommonApi {
1924
public readonly options: StreamClientOptions = {};
2025

2126
private static readonly DEFAULT_TIMEOUT = 3000;
27+
private static readonly MAX_CONNECTIONS = 100;
2228

2329
/**
2430
*
@@ -33,28 +39,39 @@ export class StreamClient extends CommonApi {
3339
) {
3440
const token = JWTServerToken(secret);
3541
const timeout = config?.timeout ?? StreamClient.DEFAULT_TIMEOUT;
42+
const agent =
43+
config?.agent ??
44+
new Agent({
45+
connections:
46+
config?.maxConnections === undefined
47+
? StreamClient.MAX_CONNECTIONS
48+
: config.maxConnections,
49+
});
3650
const chatBaseUrl = config?.basePath ?? 'https://chat.stream-io-api.com';
3751
const videoBaseUrl = config?.basePath ?? 'https://video.stream-io-api.com';
38-
super({ apiKey, token, timeout, baseUrl: chatBaseUrl });
52+
super({ apiKey, token, timeout, baseUrl: chatBaseUrl, agent });
3953

4054
this.video = new StreamVideoClient({
4155
streamClient: this,
4256
apiKey,
4357
token,
4458
timeout,
4559
baseUrl: videoBaseUrl,
60+
agent,
4661
});
4762
this.chat = new StreamChatClient({
4863
apiKey,
4964
token,
5065
timeout,
5166
baseUrl: chatBaseUrl,
67+
agent,
5268
});
5369
this.moderation = new StreamModerationClient({
5470
apiKey,
5571
token,
5672
timeout,
5773
baseUrl: chatBaseUrl,
74+
agent,
5875
});
5976
}
6077

src/gen/chat/ChannelApi.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
EventResponse,
88
FileUploadRequest,
99
FileUploadResponse,
10+
GetDraftResponse,
1011
GetManyMessagesResponse,
1112
HideChannelRequest,
1213
HideChannelResponse,
@@ -83,6 +84,34 @@ export class ChannelApi {
8384
});
8485
};
8586

87+
deleteDraft = (request?: {
88+
parent_id?: string;
89+
user_id?: string;
90+
}): Promise<StreamResponse<Response>> => {
91+
if (!this.id) {
92+
throw new Error(
93+
`Channel isn't yet created, call getOrCreateDistinctChannel() before this operation`,
94+
);
95+
}
96+
return this.chatApi.deleteDraft({
97+
id: this.id,
98+
type: this.type,
99+
...request,
100+
});
101+
};
102+
103+
getDraft = (request?: {
104+
parent_id?: string;
105+
user_id?: string;
106+
}): Promise<StreamResponse<GetDraftResponse>> => {
107+
if (!this.id) {
108+
throw new Error(
109+
`Channel isn't yet created, call getOrCreateDistinctChannel() before this operation`,
110+
);
111+
}
112+
return this.chatApi.getDraft({ id: this.id, type: this.type, ...request });
113+
};
114+
86115
sendEvent = (
87116
request: SendEventRequest,
88117
): Promise<StreamResponse<EventResponse>> => {

src/gen/chat/ChatApi.ts

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
GetCampaignResponse,
2828
GetChannelTypeResponse,
2929
GetCommandResponse,
30+
GetDraftResponse,
3031
GetManyMessagesResponse,
3132
GetMessageResponse,
3233
GetReactionsResponse,
@@ -58,6 +59,8 @@ import {
5859
QueryCampaignsResponse,
5960
QueryChannelsRequest,
6061
QueryChannelsResponse,
62+
QueryDraftsRequest,
63+
QueryDraftsResponse,
6164
QueryMembersPayload,
6265
QueryMessageFlagsPayload,
6366
QueryMessageFlagsResponse,
@@ -129,6 +132,7 @@ export class ChatApi extends BaseApi {
129132
limit: request?.limit,
130133
next: request?.next,
131134
prev: request?.prev,
135+
user_limit: request?.user_limit,
132136
sort: request?.sort,
133137
filter: request?.filter,
134138
};
@@ -144,14 +148,22 @@ export class ChatApi extends BaseApi {
144148

145149
getCampaign = async (request: {
146150
id: string;
151+
prev?: string;
152+
next?: string;
153+
limit?: number;
147154
}): Promise<StreamResponse<GetCampaignResponse>> => {
155+
const queryParams = {
156+
prev: request?.prev,
157+
next: request?.next,
158+
limit: request?.limit,
159+
};
148160
const pathParams = {
149161
id: request?.id,
150162
};
151163

152164
const response = await this.sendRequest<
153165
StreamResponse<GetCampaignResponse>
154-
>('GET', '/api/v2/chat/campaigns/{id}', pathParams, undefined);
166+
>('GET', '/api/v2/chat/campaigns/{id}', pathParams, queryParams);
155167

156168
decoders.GetCampaignResponse?.(response.body);
157169

@@ -378,6 +390,60 @@ export class ChatApi extends BaseApi {
378390
return { ...response.body, metadata: response.metadata };
379391
};
380392

393+
deleteDraft = async (request: {
394+
type: string;
395+
id: string;
396+
parent_id?: string;
397+
user_id?: string;
398+
}): Promise<StreamResponse<Response>> => {
399+
const queryParams = {
400+
parent_id: request?.parent_id,
401+
user_id: request?.user_id,
402+
};
403+
const pathParams = {
404+
type: request?.type,
405+
id: request?.id,
406+
};
407+
408+
const response = await this.sendRequest<StreamResponse<Response>>(
409+
'DELETE',
410+
'/api/v2/chat/channels/{type}/{id}/draft',
411+
pathParams,
412+
queryParams,
413+
);
414+
415+
decoders.Response?.(response.body);
416+
417+
return { ...response.body, metadata: response.metadata };
418+
};
419+
420+
getDraft = async (request: {
421+
type: string;
422+
id: string;
423+
parent_id?: string;
424+
user_id?: string;
425+
}): Promise<StreamResponse<GetDraftResponse>> => {
426+
const queryParams = {
427+
parent_id: request?.parent_id,
428+
user_id: request?.user_id,
429+
};
430+
const pathParams = {
431+
type: request?.type,
432+
id: request?.id,
433+
};
434+
435+
const response = await this.sendRequest<StreamResponse<GetDraftResponse>>(
436+
'GET',
437+
'/api/v2/chat/channels/{type}/{id}/draft',
438+
pathParams,
439+
queryParams,
440+
);
441+
442+
decoders.GetDraftResponse?.(response.body);
443+
444+
return { ...response.body, metadata: response.metadata };
445+
};
446+
381447
sendEvent = async (
382448
request: SendEventRequest & { type: string; id: string },
383449
): Promise<StreamResponse<EventResponse>> => {
@@ -991,6 +1057,28 @@ export class ChatApi extends BaseApi {
9911057
return { ...response.body, metadata: response.metadata };
9921058
};
9931059

1060+
queryDrafts = async (
1061+
request?: QueryDraftsRequest,
1062+
): Promise<StreamResponse<QueryDraftsResponse>> => {
1063+
const body = {
1064+
limit: request?.limit,
1065+
next: request?.next,
1066+
prev: request?.prev,
1067+
user_id: request?.user_id,
1068+
sort: request?.sort,
1069+
filter: request?.filter,
1070+
user: request?.user,
1071+
};
1072+
1073+
const response = await this.sendRequest<
1074+
StreamResponse<QueryDraftsResponse>
1075+
>('POST', '/api/v2/chat/drafts/query', undefined, undefined, body);
1076+
1077+
decoders.QueryDraftsResponse?.(response.body);
1078+
1079+
return { ...response.body, metadata: response.metadata };
1080+
};
1081+
9941082
exportChannels = async (
9951083
request: ExportChannelsRequest,
9961084
): Promise<StreamResponse<ExportChannelsResponse>> => {

0 commit comments

Comments
 (0)