@manonero/chat-client-sdk 1.0.0-beta.0
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/README.md +2343 -0
- package/dist/ChatClient.d.ts +122 -0
- package/dist/ChatClient.d.ts.map +1 -0
- package/dist/ChatClient.js +173 -0
- package/dist/ChatClient.js.map +1 -0
- package/dist/errors/ChatApiError.d.ts +22 -0
- package/dist/errors/ChatApiError.d.ts.map +1 -0
- package/dist/errors/ChatApiError.js +50 -0
- package/dist/errors/ChatApiError.js.map +1 -0
- package/dist/http/AuthApi.d.ts +26 -0
- package/dist/http/AuthApi.d.ts.map +1 -0
- package/dist/http/AuthApi.js +35 -0
- package/dist/http/AuthApi.js.map +1 -0
- package/dist/http/BotApi.d.ts +50 -0
- package/dist/http/BotApi.d.ts.map +1 -0
- package/dist/http/BotApi.js +67 -0
- package/dist/http/BotApi.js.map +1 -0
- package/dist/http/ConversationApi.d.ts +81 -0
- package/dist/http/ConversationApi.d.ts.map +1 -0
- package/dist/http/ConversationApi.js +115 -0
- package/dist/http/ConversationApi.js.map +1 -0
- package/dist/http/FileApi.d.ts +48 -0
- package/dist/http/FileApi.d.ts.map +1 -0
- package/dist/http/FileApi.js +68 -0
- package/dist/http/FileApi.js.map +1 -0
- package/dist/http/HealthApi.d.ts +26 -0
- package/dist/http/HealthApi.d.ts.map +1 -0
- package/dist/http/HealthApi.js +31 -0
- package/dist/http/HealthApi.js.map +1 -0
- package/dist/http/HttpClient.d.ts +51 -0
- package/dist/http/HttpClient.d.ts.map +1 -0
- package/dist/http/HttpClient.js +182 -0
- package/dist/http/HttpClient.js.map +1 -0
- package/dist/http/MessageApi.d.ts +67 -0
- package/dist/http/MessageApi.d.ts.map +1 -0
- package/dist/http/MessageApi.js +91 -0
- package/dist/http/MessageApi.js.map +1 -0
- package/dist/http/ParticipantApi.d.ts +28 -0
- package/dist/http/ParticipantApi.d.ts.map +1 -0
- package/dist/http/ParticipantApi.js +37 -0
- package/dist/http/ParticipantApi.js.map +1 -0
- package/dist/http/ProxyApi.d.ts +41 -0
- package/dist/http/ProxyApi.d.ts.map +1 -0
- package/dist/http/ProxyApi.js +57 -0
- package/dist/http/ProxyApi.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/realtime/ChatHubClient.d.ts +87 -0
- package/dist/realtime/ChatHubClient.d.ts.map +1 -0
- package/dist/realtime/ChatHubClient.js +182 -0
- package/dist/realtime/ChatHubClient.js.map +1 -0
- package/dist/realtime/NotificationHubClient.d.ts +73 -0
- package/dist/realtime/NotificationHubClient.d.ts.map +1 -0
- package/dist/realtime/NotificationHubClient.js +162 -0
- package/dist/realtime/NotificationHubClient.js.map +1 -0
- package/dist/realtime/ReconnectionManager.d.ts +65 -0
- package/dist/realtime/ReconnectionManager.d.ts.map +1 -0
- package/dist/realtime/ReconnectionManager.js +118 -0
- package/dist/realtime/ReconnectionManager.js.map +1 -0
- package/dist/types/auth.d.ts +28 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +3 -0
- package/dist/types/auth.js.map +1 -0
- package/dist/types/block.d.ts +148 -0
- package/dist/types/block.d.ts.map +1 -0
- package/dist/types/block.js +47 -0
- package/dist/types/block.js.map +1 -0
- package/dist/types/bot.d.ts +48 -0
- package/dist/types/bot.d.ts.map +1 -0
- package/dist/types/bot.js +3 -0
- package/dist/types/bot.js.map +1 -0
- package/dist/types/chat-events.d.ts +153 -0
- package/dist/types/chat-events.d.ts.map +1 -0
- package/dist/types/chat-events.js +3 -0
- package/dist/types/chat-events.js.map +1 -0
- package/dist/types/common.d.ts +57 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +3 -0
- package/dist/types/common.js.map +1 -0
- package/dist/types/conversation.d.ts +70 -0
- package/dist/types/conversation.d.ts.map +1 -0
- package/dist/types/conversation.js +3 -0
- package/dist/types/conversation.js.map +1 -0
- package/dist/types/file.d.ts +31 -0
- package/dist/types/file.d.ts.map +1 -0
- package/dist/types/file.js +3 -0
- package/dist/types/file.js.map +1 -0
- package/dist/types/message.d.ts +83 -0
- package/dist/types/message.d.ts.map +1 -0
- package/dist/types/message.js +3 -0
- package/dist/types/message.js.map +1 -0
- package/dist/types/notification-events.d.ts +97 -0
- package/dist/types/notification-events.d.ts.map +1 -0
- package/dist/types/notification-events.js +3 -0
- package/dist/types/notification-events.js.map +1 -0
- package/dist/types/participant.d.ts +25 -0
- package/dist/types/participant.d.ts.map +1 -0
- package/dist/types/participant.js +3 -0
- package/dist/types/participant.js.map +1 -0
- package/dist/types/signalr.d.ts +87 -0
- package/dist/types/signalr.d.ts.map +1 -0
- package/dist/types/signalr.js +3 -0
- package/dist/types/signalr.js.map +1 -0
- package/dist/utils/TypedEventEmitter.d.ts +32 -0
- package/dist/utils/TypedEventEmitter.d.ts.map +1 -0
- package/dist/utils/TypedEventEmitter.js +60 -0
- package/dist/utils/TypedEventEmitter.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
import type { ConversationDto, ConversationListItemDto, ConversationParticipantDto, CreateConversationRequest, UpdateConversationRequest, AddParticipantRequest } from '../types/conversation.js';
|
|
3
|
+
import type { PaginatedResult } from '../types/common.js';
|
|
4
|
+
/**
|
|
5
|
+
* Conversation API client.
|
|
6
|
+
* All endpoints require JWT Bearer token.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ConversationApi {
|
|
9
|
+
private readonly http;
|
|
10
|
+
constructor(http: HttpClient);
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/conversations?limit={limit}&cursor={cursor}
|
|
13
|
+
*
|
|
14
|
+
* Returns paginated conversations sorted by:
|
|
15
|
+
* 1. Pinned conversations first (by pinnedAt desc)
|
|
16
|
+
* 2. Then by lastMessageAt desc
|
|
17
|
+
*
|
|
18
|
+
* Each item includes the full lastMessage (MessageDto) for preview.
|
|
19
|
+
* NOTE: cursor is a string representing .NET DateTime ticks — do NOT cast to number.
|
|
20
|
+
*/
|
|
21
|
+
list(params?: {
|
|
22
|
+
limit?: number;
|
|
23
|
+
cursor?: string;
|
|
24
|
+
}): Promise<PaginatedResult<ConversationListItemDto>>;
|
|
25
|
+
/** POST /api/conversations */
|
|
26
|
+
create(request: CreateConversationRequest): Promise<ConversationDto>;
|
|
27
|
+
/**
|
|
28
|
+
* GET /api/conversations/search?q={query}&limit={limit}
|
|
29
|
+
* Search conversations by name or participant name.
|
|
30
|
+
*/
|
|
31
|
+
search(query: string, limit?: number): Promise<ConversationListItemDto[]>;
|
|
32
|
+
/** GET /api/conversations/{id} */
|
|
33
|
+
getById(id: string): Promise<ConversationDto>;
|
|
34
|
+
/**
|
|
35
|
+
* PATCH /api/conversations/{id}
|
|
36
|
+
* Only applicable for Group conversations.
|
|
37
|
+
*/
|
|
38
|
+
update(id: string, request: UpdateConversationRequest): Promise<ConversationDto>;
|
|
39
|
+
/**
|
|
40
|
+
* DELETE /api/conversations/{id}
|
|
41
|
+
* Leave the conversation. Does NOT delete it — other participants remain.
|
|
42
|
+
*/
|
|
43
|
+
leave(id: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* GET /api/conversations/one-to-one/{otherParticipantId}
|
|
46
|
+
* Find an existing OneToOne conversation with another participant.
|
|
47
|
+
* Returns null (204 No Content) when no such conversation exists yet.
|
|
48
|
+
*/
|
|
49
|
+
findOneToOne(otherParticipantId: string): Promise<ConversationDto | null>;
|
|
50
|
+
/**
|
|
51
|
+
* POST /api/conversations/{id}/participants
|
|
52
|
+
* Add a participant to a Group conversation.
|
|
53
|
+
* canViewHistory defaults to true (can see messages before joining).
|
|
54
|
+
*/
|
|
55
|
+
addParticipant(conversationId: string, request: AddParticipantRequest): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* DELETE /api/conversations/{id}/participants/{participantId}
|
|
58
|
+
* Remove a participant from a Group conversation.
|
|
59
|
+
*/
|
|
60
|
+
removeParticipant(conversationId: string, participantId: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* GET /api/conversations/{id}/participants
|
|
63
|
+
* Returns all participants (including those who have left).
|
|
64
|
+
*/
|
|
65
|
+
getParticipants(conversationId: string): Promise<ConversationParticipantDto[]>;
|
|
66
|
+
/** POST /api/conversations/{id}/pin */
|
|
67
|
+
pin(id: string): Promise<void>;
|
|
68
|
+
/** DELETE /api/conversations/{id}/pin */
|
|
69
|
+
unpin(id: string): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* POST /api/conversations/{id}/read
|
|
72
|
+
* Mark a conversation as read up to the given messageId.
|
|
73
|
+
*/
|
|
74
|
+
markAsRead(id: string, messageId: string): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* DELETE /api/conversations/{id}/read
|
|
77
|
+
* Mark the conversation as unread (user-initiated).
|
|
78
|
+
*/
|
|
79
|
+
markAsUnread(id: string): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=ConversationApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationApi.d.ts","sourceRoot":"","sources":["../../src/http/ConversationApi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EACV,eAAe,EACf,uBAAuB,EACvB,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;;;;;;;OASG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,eAAe,CAAC,uBAAuB,CAAC,CAAC;IAUrD,8BAA8B;IAC9B,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC;IAIpE;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAMzE,kCAAkC;IAClC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAI7C;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC;IAIhF;;;OAGG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;OAIG;IACH,YAAY,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;IAMzE;;;;OAIG;IACH,cAAc,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOrF;;;OAGG;IACH,iBAAiB,CAAC,cAAc,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/E;;;OAGG;IACH,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAM9E,uCAAuC;IACvC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9B,yCAAyC;IACzC,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;;OAGG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGxC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// ConversationApi.ts — Conversation management endpoints
|
|
2
|
+
import { HttpClient } from './HttpClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* Conversation API client.
|
|
5
|
+
* All endpoints require JWT Bearer token.
|
|
6
|
+
*/
|
|
7
|
+
export class ConversationApi {
|
|
8
|
+
constructor(http) {
|
|
9
|
+
this.http = http;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* GET /api/conversations?limit={limit}&cursor={cursor}
|
|
13
|
+
*
|
|
14
|
+
* Returns paginated conversations sorted by:
|
|
15
|
+
* 1. Pinned conversations first (by pinnedAt desc)
|
|
16
|
+
* 2. Then by lastMessageAt desc
|
|
17
|
+
*
|
|
18
|
+
* Each item includes the full lastMessage (MessageDto) for preview.
|
|
19
|
+
* NOTE: cursor is a string representing .NET DateTime ticks — do NOT cast to number.
|
|
20
|
+
*/
|
|
21
|
+
list(params) {
|
|
22
|
+
const qs = new URLSearchParams();
|
|
23
|
+
if (params?.limit !== undefined)
|
|
24
|
+
qs.set('limit', String(params.limit));
|
|
25
|
+
if (params?.cursor !== undefined)
|
|
26
|
+
qs.set('cursor', params.cursor);
|
|
27
|
+
const q = qs.toString();
|
|
28
|
+
return this.http.get(`/api/conversations${q ? `?${q}` : ''}`);
|
|
29
|
+
}
|
|
30
|
+
/** POST /api/conversations */
|
|
31
|
+
create(request) {
|
|
32
|
+
return this.http.post('/api/conversations', request);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* GET /api/conversations/search?q={query}&limit={limit}
|
|
36
|
+
* Search conversations by name or participant name.
|
|
37
|
+
*/
|
|
38
|
+
search(query, limit) {
|
|
39
|
+
const qs = new URLSearchParams({ q: query });
|
|
40
|
+
if (limit !== undefined)
|
|
41
|
+
qs.set('limit', String(limit));
|
|
42
|
+
return this.http.get(`/api/conversations/search?${qs.toString()}`);
|
|
43
|
+
}
|
|
44
|
+
/** GET /api/conversations/{id} */
|
|
45
|
+
getById(id) {
|
|
46
|
+
return this.http.get(`/api/conversations/${encodeURIComponent(id)}`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* PATCH /api/conversations/{id}
|
|
50
|
+
* Only applicable for Group conversations.
|
|
51
|
+
*/
|
|
52
|
+
update(id, request) {
|
|
53
|
+
return this.http.patch(`/api/conversations/${encodeURIComponent(id)}`, request);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* DELETE /api/conversations/{id}
|
|
57
|
+
* Leave the conversation. Does NOT delete it — other participants remain.
|
|
58
|
+
*/
|
|
59
|
+
leave(id) {
|
|
60
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(id)}`);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* GET /api/conversations/one-to-one/{otherParticipantId}
|
|
64
|
+
* Find an existing OneToOne conversation with another participant.
|
|
65
|
+
* Returns null (204 No Content) when no such conversation exists yet.
|
|
66
|
+
*/
|
|
67
|
+
findOneToOne(otherParticipantId) {
|
|
68
|
+
return this.http.get(`/api/conversations/one-to-one/${encodeURIComponent(otherParticipantId)}`);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* POST /api/conversations/{id}/participants
|
|
72
|
+
* Add a participant to a Group conversation.
|
|
73
|
+
* canViewHistory defaults to true (can see messages before joining).
|
|
74
|
+
*/
|
|
75
|
+
addParticipant(conversationId, request) {
|
|
76
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(conversationId)}/participants`, request);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* DELETE /api/conversations/{id}/participants/{participantId}
|
|
80
|
+
* Remove a participant from a Group conversation.
|
|
81
|
+
*/
|
|
82
|
+
removeParticipant(conversationId, participantId) {
|
|
83
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(conversationId)}/participants/${encodeURIComponent(participantId)}`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* GET /api/conversations/{id}/participants
|
|
87
|
+
* Returns all participants (including those who have left).
|
|
88
|
+
*/
|
|
89
|
+
getParticipants(conversationId) {
|
|
90
|
+
return this.http.get(`/api/conversations/${encodeURIComponent(conversationId)}/participants`);
|
|
91
|
+
}
|
|
92
|
+
/** POST /api/conversations/{id}/pin */
|
|
93
|
+
pin(id) {
|
|
94
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(id)}/pin`);
|
|
95
|
+
}
|
|
96
|
+
/** DELETE /api/conversations/{id}/pin */
|
|
97
|
+
unpin(id) {
|
|
98
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(id)}/pin`);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* POST /api/conversations/{id}/read
|
|
102
|
+
* Mark a conversation as read up to the given messageId.
|
|
103
|
+
*/
|
|
104
|
+
markAsRead(id, messageId) {
|
|
105
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(id)}/read`, { messageId });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* DELETE /api/conversations/{id}/read
|
|
109
|
+
* Mark the conversation as unread (user-initiated).
|
|
110
|
+
*/
|
|
111
|
+
markAsUnread(id) {
|
|
112
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(id)}/read`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=ConversationApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConversationApi.js","sourceRoot":"","sources":["../../src/http/ConversationApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
import type { CreateUploadUrlRequest, CreateUploadUrlResponse, UploadResponse } from '../types/file.js';
|
|
3
|
+
import type { UploadProgressCallback } from '../types/common.js';
|
|
4
|
+
/**
|
|
5
|
+
* File API client.
|
|
6
|
+
* Upload endpoints require JWT Bearer token.
|
|
7
|
+
* Download (GET /api/files/*) is public — no JWT required.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FileApi {
|
|
10
|
+
private readonly http;
|
|
11
|
+
constructor(http: HttpClient);
|
|
12
|
+
/**
|
|
13
|
+
* POST /api/files/upload-url
|
|
14
|
+
* Request a presigned upload URL. Returns a relative uploadUrl that must
|
|
15
|
+
* be combined with baseUrl before calling upload().
|
|
16
|
+
*/
|
|
17
|
+
createUploadUrl(request: CreateUploadUrlRequest): Promise<CreateUploadUrlResponse>;
|
|
18
|
+
/**
|
|
19
|
+
* POST {uploadUrl} (relative URL from createUploadUrl response)
|
|
20
|
+
* Upload the file using multipart/form-data under the field name "file".
|
|
21
|
+
*
|
|
22
|
+
* When onProgress is provided, XHR is used (supports upload progress events).
|
|
23
|
+
* Otherwise fetch is used.
|
|
24
|
+
*
|
|
25
|
+
* NOTE: uploadUrl from the server is a relative path like "/api/files/upload?key=...&sig=...".
|
|
26
|
+
* HttpClient.buildUrl() automatically prepends baseUrl for relative paths.
|
|
27
|
+
*/
|
|
28
|
+
upload(uploadUrl: string, file: File | Blob, onProgress?: UploadProgressCallback): Promise<UploadResponse>;
|
|
29
|
+
/**
|
|
30
|
+
* Returns the absolute download URL for a given storageKey.
|
|
31
|
+
* Download is public — no auth required.
|
|
32
|
+
* Example: storageKey "01HXABCDEF/photo.jpg" → "{baseUrl}/api/files/01HXABCDEF/photo.jpg"
|
|
33
|
+
*/
|
|
34
|
+
getDownloadUrl(storageKey: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* DELETE /api/files/{storageKey}
|
|
37
|
+
* Delete an uploaded file. Only the uploader can delete.
|
|
38
|
+
* storageKey may contain path separators (e.g. "01HXABCDEF/photo.jpg") — do NOT encode it.
|
|
39
|
+
*/
|
|
40
|
+
delete(storageKey: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Convenience method: create upload URL then immediately upload the file.
|
|
43
|
+
* Equivalent to calling createUploadUrl() + upload() in sequence.
|
|
44
|
+
* onProgress is forwarded to the upload step.
|
|
45
|
+
*/
|
|
46
|
+
uploadFile(file: File, onProgress?: UploadProgressCallback): Promise<UploadResponse>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=FileApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileApi.d.ts","sourceRoot":"","sources":["../../src/http/FileApi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EACV,sBAAsB,EACtB,uBAAuB,EACvB,cAAc,EACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEjE;;;;GAIG;AACH,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;;OAIG;IACH,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAIlF;;;;;;;;;OASG;IACH,MAAM,CACJ,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,UAAU,CAAC,EAAE,sBAAsB,GAClC,OAAO,CAAC,cAAc,CAAC;IAS1B;;;;OAIG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAI1C;;;;OAIG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,cAAc,CAAC;CAQ3F"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// FileApi.ts — File upload/download endpoints
|
|
2
|
+
import { HttpClient } from './HttpClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* File API client.
|
|
5
|
+
* Upload endpoints require JWT Bearer token.
|
|
6
|
+
* Download (GET /api/files/*) is public — no JWT required.
|
|
7
|
+
*/
|
|
8
|
+
export class FileApi {
|
|
9
|
+
constructor(http) {
|
|
10
|
+
this.http = http;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* POST /api/files/upload-url
|
|
14
|
+
* Request a presigned upload URL. Returns a relative uploadUrl that must
|
|
15
|
+
* be combined with baseUrl before calling upload().
|
|
16
|
+
*/
|
|
17
|
+
createUploadUrl(request) {
|
|
18
|
+
return this.http.post('/api/files/upload-url', request);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* POST {uploadUrl} (relative URL from createUploadUrl response)
|
|
22
|
+
* Upload the file using multipart/form-data under the field name "file".
|
|
23
|
+
*
|
|
24
|
+
* When onProgress is provided, XHR is used (supports upload progress events).
|
|
25
|
+
* Otherwise fetch is used.
|
|
26
|
+
*
|
|
27
|
+
* NOTE: uploadUrl from the server is a relative path like "/api/files/upload?key=...&sig=...".
|
|
28
|
+
* HttpClient.buildUrl() automatically prepends baseUrl for relative paths.
|
|
29
|
+
*/
|
|
30
|
+
upload(uploadUrl, file, onProgress) {
|
|
31
|
+
const formData = new FormData();
|
|
32
|
+
formData.append('file', file);
|
|
33
|
+
if (onProgress) {
|
|
34
|
+
return this.http.postFormDataWithProgress(uploadUrl, formData, onProgress);
|
|
35
|
+
}
|
|
36
|
+
return this.http.postFormData(uploadUrl, formData);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returns the absolute download URL for a given storageKey.
|
|
40
|
+
* Download is public — no auth required.
|
|
41
|
+
* Example: storageKey "01HXABCDEF/photo.jpg" → "{baseUrl}/api/files/01HXABCDEF/photo.jpg"
|
|
42
|
+
*/
|
|
43
|
+
getDownloadUrl(storageKey) {
|
|
44
|
+
return `${this.http.baseUrl}/api/files/${storageKey}`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* DELETE /api/files/{storageKey}
|
|
48
|
+
* Delete an uploaded file. Only the uploader can delete.
|
|
49
|
+
* storageKey may contain path separators (e.g. "01HXABCDEF/photo.jpg") — do NOT encode it.
|
|
50
|
+
*/
|
|
51
|
+
delete(storageKey) {
|
|
52
|
+
return this.http.delete(`/api/files/${storageKey}`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Convenience method: create upload URL then immediately upload the file.
|
|
56
|
+
* Equivalent to calling createUploadUrl() + upload() in sequence.
|
|
57
|
+
* onProgress is forwarded to the upload step.
|
|
58
|
+
*/
|
|
59
|
+
async uploadFile(file, onProgress) {
|
|
60
|
+
const { uploadUrl } = await this.createUploadUrl({
|
|
61
|
+
fileName: file.name,
|
|
62
|
+
contentType: file.type,
|
|
63
|
+
fileSize: file.size,
|
|
64
|
+
});
|
|
65
|
+
return this.upload(uploadUrl, file, onProgress);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=FileApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileApi.js","sourceRoot":"","sources":["../../src/http/FileApi.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAE9C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C;;;;GAIG;AACH,MAAM,OAAO,OAAO;IAGlB,YAAY,IAAgB;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,eAAe,CAAC,OAA+B;QAC7C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAA0B,uBAAuB,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC;IAED;;;;;;;;;OASG;IACH,MAAM,CACJ,SAAiB,EACjB,IAAiB,EACjB,UAAmC;QAEnC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC9B,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAiB,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,CAAiB,SAAS,EAAE,QAAQ,CAAC,CAAC;IACrE,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,UAAkB;QAC/B,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,cAAc,UAAU,EAAE,CAAC;IACxD,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,UAAkB;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAO,cAAc,UAAU,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,IAAU,EAAE,UAAmC;QAC9D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC;YAC/C,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,WAAW,EAAE,IAAI,CAAC,IAAI;YACtB,QAAQ,EAAE,IAAI,CAAC,IAAI;SACpB,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
import type { HealthStatus } from '../types/common.js';
|
|
3
|
+
/**
|
|
4
|
+
* Health check API client.
|
|
5
|
+
* All endpoints are public — no JWT required.
|
|
6
|
+
*/
|
|
7
|
+
export declare class HealthApi {
|
|
8
|
+
private readonly http;
|
|
9
|
+
constructor(http: HttpClient);
|
|
10
|
+
/**
|
|
11
|
+
* GET /health/live
|
|
12
|
+
* Liveness probe — returns the plain text string "Healthy" when the server is up.
|
|
13
|
+
* Use this to check if the process is running (not whether dependencies are healthy).
|
|
14
|
+
*/
|
|
15
|
+
live(): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* GET /health/ready
|
|
18
|
+
* Readiness probe — returns detailed status for all dependencies
|
|
19
|
+
* (MongoDB, Redis, Kafka). Use this to check if the server can serve traffic.
|
|
20
|
+
*
|
|
21
|
+
* status values: "Healthy" | "Degraded" | "Unhealthy"
|
|
22
|
+
* durations are .NET TimeSpan strings (e.g. "00:00:00.1234567"), NOT numbers.
|
|
23
|
+
*/
|
|
24
|
+
ready(): Promise<HealthStatus>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=HealthApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HealthApi.d.ts","sourceRoot":"","sources":["../../src/http/HealthApi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;;OAIG;IACH,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvB;;;;;;;OAOG;IACH,KAAK,IAAI,OAAO,CAAC,YAAY,CAAC;CAG/B"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// HealthApi.ts — Health check endpoints
|
|
2
|
+
import { HttpClient } from './HttpClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* Health check API client.
|
|
5
|
+
* All endpoints are public — no JWT required.
|
|
6
|
+
*/
|
|
7
|
+
export class HealthApi {
|
|
8
|
+
constructor(http) {
|
|
9
|
+
this.http = http;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* GET /health/live
|
|
13
|
+
* Liveness probe — returns the plain text string "Healthy" when the server is up.
|
|
14
|
+
* Use this to check if the process is running (not whether dependencies are healthy).
|
|
15
|
+
*/
|
|
16
|
+
live() {
|
|
17
|
+
return this.http.getText('/health/live');
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* GET /health/ready
|
|
21
|
+
* Readiness probe — returns detailed status for all dependencies
|
|
22
|
+
* (MongoDB, Redis, Kafka). Use this to check if the server can serve traffic.
|
|
23
|
+
*
|
|
24
|
+
* status values: "Healthy" | "Degraded" | "Unhealthy"
|
|
25
|
+
* durations are .NET TimeSpan strings (e.g. "00:00:00.1234567"), NOT numbers.
|
|
26
|
+
*/
|
|
27
|
+
ready() {
|
|
28
|
+
return this.http.get('/health/ready');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=HealthApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HealthApi.js","sourceRoot":"","sources":["../../src/http/HealthApi.ts"],"names":[],"mappings":"AAAA,wCAAwC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C;;;GAGG;AACH,MAAM,OAAO,SAAS;IAGpB,YAAY,IAAgB;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;OAOG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAe,eAAe,CAAC,CAAC;IACtD,CAAC;CACF"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { UploadProgressCallback } from '../types/common.js';
|
|
2
|
+
export interface HttpClientOptions {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
/** Returns the current JWT token, or null if not authenticated */
|
|
5
|
+
tokenProvider?: () => string | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Base HTTP client wrapping the Fetch API.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Automatic Authorization: Bearer token injection via tokenProvider
|
|
12
|
+
* - JSON request/response serialization
|
|
13
|
+
* - Throws ChatApiError on non-OK responses
|
|
14
|
+
* - Handles empty responses (204 No Content, 200 with no body)
|
|
15
|
+
* - Multipart file upload with optional XHR-based upload progress
|
|
16
|
+
*/
|
|
17
|
+
export declare class HttpClient {
|
|
18
|
+
readonly baseUrl: string;
|
|
19
|
+
private readonly tokenProvider;
|
|
20
|
+
constructor(options: HttpClientOptions);
|
|
21
|
+
private buildUrl;
|
|
22
|
+
private buildHeaders;
|
|
23
|
+
private buildAuthHeader;
|
|
24
|
+
/**
|
|
25
|
+
* Parse response body safely.
|
|
26
|
+
* Returns null for 204 No Content or empty bodies.
|
|
27
|
+
*/
|
|
28
|
+
private parseBody;
|
|
29
|
+
private handleResponse;
|
|
30
|
+
get<T>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
31
|
+
/**
|
|
32
|
+
* GET a plain-text response (e.g. /health/live which returns "Healthy").
|
|
33
|
+
* Unlike get<T>(), this does not attempt JSON parsing.
|
|
34
|
+
*/
|
|
35
|
+
getText(path: string): Promise<string>;
|
|
36
|
+
post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
37
|
+
patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
38
|
+
delete<T>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
39
|
+
/**
|
|
40
|
+
* POST with multipart/form-data — no explicit Content-Type header
|
|
41
|
+
* (browser sets it with the boundary automatically).
|
|
42
|
+
*/
|
|
43
|
+
postFormData<T>(path: string, formData: FormData): Promise<T>;
|
|
44
|
+
/**
|
|
45
|
+
* POST with multipart/form-data and upload progress reporting.
|
|
46
|
+
* Uses XMLHttpRequest instead of fetch because fetch does not support
|
|
47
|
+
* upload progress events.
|
|
48
|
+
*/
|
|
49
|
+
postFormDataWithProgress<T>(path: string, formData: FormData, onProgress?: UploadProgressCallback): Promise<T>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=HttpClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.d.ts","sourceRoot":"","sources":["../../src/http/HttpClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;gBAExC,OAAO,EAAE,iBAAiB;IAUtC,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,eAAe;IAQvB;;;OAGG;YACW,SAAS;YAST,cAAc;IAatB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQxE;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAWtC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IASnF,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IASpF,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQ3E;;;OAGG;IACG,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC;IASnE;;;;OAIG;IACH,wBAAwB,CAAC,CAAC,EACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,QAAQ,EAClB,UAAU,CAAC,EAAE,sBAAsB,GAClC,OAAO,CAAC,CAAC,CAAC;CAoDd"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// HttpClient.ts — Base HTTP client (fetch wrapper)
|
|
2
|
+
import { ChatApiError } from '../errors/ChatApiError.js';
|
|
3
|
+
/**
|
|
4
|
+
* Base HTTP client wrapping the Fetch API.
|
|
5
|
+
*
|
|
6
|
+
* Features:
|
|
7
|
+
* - Automatic Authorization: Bearer token injection via tokenProvider
|
|
8
|
+
* - JSON request/response serialization
|
|
9
|
+
* - Throws ChatApiError on non-OK responses
|
|
10
|
+
* - Handles empty responses (204 No Content, 200 with no body)
|
|
11
|
+
* - Multipart file upload with optional XHR-based upload progress
|
|
12
|
+
*/
|
|
13
|
+
export class HttpClient {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
// Strip trailing slash for consistent URL joining
|
|
16
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
17
|
+
this.tokenProvider = options.tokenProvider ?? (() => null);
|
|
18
|
+
}
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Private helpers
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
buildUrl(path) {
|
|
23
|
+
// If path already looks absolute, use it directly
|
|
24
|
+
if (path.startsWith('http://') || path.startsWith('https://')) {
|
|
25
|
+
return path;
|
|
26
|
+
}
|
|
27
|
+
// Ensure exactly one slash between base and path
|
|
28
|
+
const separator = path.startsWith('/') ? '' : '/';
|
|
29
|
+
return `${this.baseUrl}${separator}${path}`;
|
|
30
|
+
}
|
|
31
|
+
buildHeaders(extra) {
|
|
32
|
+
const headers = {
|
|
33
|
+
'Content-Type': 'application/json',
|
|
34
|
+
...extra,
|
|
35
|
+
};
|
|
36
|
+
const token = this.tokenProvider();
|
|
37
|
+
if (token) {
|
|
38
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
39
|
+
}
|
|
40
|
+
return headers;
|
|
41
|
+
}
|
|
42
|
+
buildAuthHeader() {
|
|
43
|
+
const token = this.tokenProvider();
|
|
44
|
+
if (token) {
|
|
45
|
+
return { Authorization: `Bearer ${token}` };
|
|
46
|
+
}
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse response body safely.
|
|
51
|
+
* Returns null for 204 No Content or empty bodies.
|
|
52
|
+
*/
|
|
53
|
+
async parseBody(response) {
|
|
54
|
+
if (response.status === 204)
|
|
55
|
+
return null;
|
|
56
|
+
const text = await response.text();
|
|
57
|
+
if (!text || text.trim() === '')
|
|
58
|
+
return null;
|
|
59
|
+
return JSON.parse(text);
|
|
60
|
+
}
|
|
61
|
+
async handleResponse(response) {
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
throw await ChatApiError.fromResponse(response);
|
|
64
|
+
}
|
|
65
|
+
// Reuse the body text that was already consumed — clone before parseBody
|
|
66
|
+
const result = await this.parseBody(response);
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Public methods
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
async get(path, headers) {
|
|
73
|
+
const response = await fetch(this.buildUrl(path), {
|
|
74
|
+
method: 'GET',
|
|
75
|
+
headers: { ...this.buildAuthHeader(), ...headers },
|
|
76
|
+
});
|
|
77
|
+
return this.handleResponse(response);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* GET a plain-text response (e.g. /health/live which returns "Healthy").
|
|
81
|
+
* Unlike get<T>(), this does not attempt JSON parsing.
|
|
82
|
+
*/
|
|
83
|
+
async getText(path) {
|
|
84
|
+
const response = await fetch(this.buildUrl(path), {
|
|
85
|
+
method: 'GET',
|
|
86
|
+
headers: { ...this.buildAuthHeader() },
|
|
87
|
+
});
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw await ChatApiError.fromResponse(response);
|
|
90
|
+
}
|
|
91
|
+
return response.text();
|
|
92
|
+
}
|
|
93
|
+
async post(path, body, headers) {
|
|
94
|
+
const response = await fetch(this.buildUrl(path), {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { ...this.buildHeaders(headers) },
|
|
97
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
98
|
+
});
|
|
99
|
+
return this.handleResponse(response);
|
|
100
|
+
}
|
|
101
|
+
async patch(path, body, headers) {
|
|
102
|
+
const response = await fetch(this.buildUrl(path), {
|
|
103
|
+
method: 'PATCH',
|
|
104
|
+
headers: { ...this.buildHeaders(headers) },
|
|
105
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
106
|
+
});
|
|
107
|
+
return this.handleResponse(response);
|
|
108
|
+
}
|
|
109
|
+
async delete(path, headers) {
|
|
110
|
+
const response = await fetch(this.buildUrl(path), {
|
|
111
|
+
method: 'DELETE',
|
|
112
|
+
headers: { ...this.buildAuthHeader(), ...headers },
|
|
113
|
+
});
|
|
114
|
+
return this.handleResponse(response);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* POST with multipart/form-data — no explicit Content-Type header
|
|
118
|
+
* (browser sets it with the boundary automatically).
|
|
119
|
+
*/
|
|
120
|
+
async postFormData(path, formData) {
|
|
121
|
+
const response = await fetch(this.buildUrl(path), {
|
|
122
|
+
method: 'POST',
|
|
123
|
+
headers: { ...this.buildAuthHeader() },
|
|
124
|
+
body: formData,
|
|
125
|
+
});
|
|
126
|
+
return this.handleResponse(response);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* POST with multipart/form-data and upload progress reporting.
|
|
130
|
+
* Uses XMLHttpRequest instead of fetch because fetch does not support
|
|
131
|
+
* upload progress events.
|
|
132
|
+
*/
|
|
133
|
+
postFormDataWithProgress(path, formData, onProgress) {
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const xhr = new XMLHttpRequest();
|
|
136
|
+
xhr.open('POST', this.buildUrl(path));
|
|
137
|
+
const token = this.tokenProvider();
|
|
138
|
+
if (token) {
|
|
139
|
+
xhr.setRequestHeader('Authorization', `Bearer ${token}`);
|
|
140
|
+
}
|
|
141
|
+
if (onProgress) {
|
|
142
|
+
xhr.upload.onprogress = (event) => {
|
|
143
|
+
if (event.lengthComputable) {
|
|
144
|
+
onProgress(event.loaded, event.total);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
xhr.onload = () => {
|
|
149
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
150
|
+
if (xhr.status === 204 || !xhr.responseText || xhr.responseText.trim() === '') {
|
|
151
|
+
resolve(null);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
try {
|
|
155
|
+
resolve(JSON.parse(xhr.responseText));
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
reject(new ChatApiError(xhr.status, 'Parse Error', 'Failed to parse response JSON'));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Build a minimal Response-like object to reuse ChatApiError.fromResponse
|
|
164
|
+
const syntheticResponse = new Response(xhr.responseText, {
|
|
165
|
+
status: xhr.status,
|
|
166
|
+
statusText: xhr.statusText,
|
|
167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
168
|
+
});
|
|
169
|
+
ChatApiError.fromResponse(syntheticResponse).then(reject).catch(reject);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
xhr.onerror = () => {
|
|
173
|
+
reject(new ChatApiError(0, 'Network Error', 'Request failed due to a network error'));
|
|
174
|
+
};
|
|
175
|
+
xhr.ontimeout = () => {
|
|
176
|
+
reject(new ChatApiError(0, 'Timeout', 'Request timed out'));
|
|
177
|
+
};
|
|
178
|
+
xhr.send(formData);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=HttpClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HttpClient.js","sourceRoot":"","sources":["../../src/http/HttpClient.ts"],"names":[],"mappings":"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"}
|