@manonero/chat-client-sdk 0.0.1-beta.1
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 +2453 -0
- package/dist/ChatClient.d.ts +181 -0
- package/dist/ChatClient.d.ts.map +1 -0
- package/dist/ChatClient.js +246 -0
- package/dist/ChatClient.js.map +1 -0
- package/dist/errors/ChatApiError.d.ts +45 -0
- package/dist/errors/ChatApiError.d.ts.map +1 -0
- package/dist/errors/ChatApiError.js +69 -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 +43 -0
- package/dist/http/BotApi.d.ts.map +1 -0
- package/dist/http/BotApi.js +60 -0
- package/dist/http/BotApi.js.map +1 -0
- package/dist/http/ConversationApi.d.ts +92 -0
- package/dist/http/ConversationApi.d.ts.map +1 -0
- package/dist/http/ConversationApi.js +128 -0
- package/dist/http/ConversationApi.js.map +1 -0
- package/dist/http/FileApi.d.ts +60 -0
- package/dist/http/FileApi.d.ts.map +1 -0
- package/dist/http/FileApi.js +91 -0
- package/dist/http/FileApi.js.map +1 -0
- package/dist/http/HealthApi.d.ts +28 -0
- package/dist/http/HealthApi.d.ts.map +1 -0
- package/dist/http/HealthApi.js +34 -0
- package/dist/http/HealthApi.js.map +1 -0
- package/dist/http/HttpClient.d.ts +69 -0
- package/dist/http/HttpClient.d.ts.map +1 -0
- package/dist/http/HttpClient.js +244 -0
- package/dist/http/HttpClient.js.map +1 -0
- package/dist/http/MessageApi.d.ts +69 -0
- package/dist/http/MessageApi.d.ts.map +1 -0
- package/dist/http/MessageApi.js +104 -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 +59 -0
- package/dist/http/ProxyApi.d.ts.map +1 -0
- package/dist/http/ProxyApi.js +86 -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 +143 -0
- package/dist/realtime/ChatHubClient.d.ts.map +1 -0
- package/dist/realtime/ChatHubClient.js +365 -0
- package/dist/realtime/ChatHubClient.js.map +1 -0
- package/dist/realtime/NotificationHubClient.d.ts +89 -0
- package/dist/realtime/NotificationHubClient.d.ts.map +1 -0
- package/dist/realtime/NotificationHubClient.js +191 -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 +129 -0
- package/dist/realtime/ReconnectionManager.js.map +1 -0
- package/dist/types/auth.d.ts +30 -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 +163 -0
- package/dist/types/block.d.ts.map +1 -0
- package/dist/types/block.js +77 -0
- package/dist/types/block.js.map +1 -0
- package/dist/types/bot.d.ts +42 -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 +191 -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 +64 -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 +106 -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 +84 -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 +89 -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 +22 -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 +84 -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 +42 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
import type { BotDto, CreateBotRequest, UpdateBotRequest } from '../types/bot.js';
|
|
3
|
+
import type { PagedResult } from '../types/common.js';
|
|
4
|
+
/**
|
|
5
|
+
* Bot API client.
|
|
6
|
+
*
|
|
7
|
+
* GET endpoints (list, getById) are public — no JWT required.
|
|
8
|
+
* Management endpoints (create, update, activate, deactivate, delete)
|
|
9
|
+
* require JWT with claim role=dev (obtained via loginWithDev).
|
|
10
|
+
* Non-dev users receive 404 Not Found on management endpoints.
|
|
11
|
+
*/
|
|
12
|
+
export declare class BotApi {
|
|
13
|
+
private readonly http;
|
|
14
|
+
constructor(http: HttpClient);
|
|
15
|
+
/**
|
|
16
|
+
* GET /api/bots?page={page}&pageSize={pageSize}
|
|
17
|
+
* List all bots (public).
|
|
18
|
+
* page is 1-based.
|
|
19
|
+
*/
|
|
20
|
+
list(params?: {
|
|
21
|
+
page?: number;
|
|
22
|
+
pageSize?: number;
|
|
23
|
+
}): Promise<PagedResult<BotDto>>;
|
|
24
|
+
/** GET /api/bots/{id} (public) */
|
|
25
|
+
getById(id: string): Promise<BotDto>;
|
|
26
|
+
/**
|
|
27
|
+
* POST /api/bots (dev-only)
|
|
28
|
+
* Register a new bot.
|
|
29
|
+
*/
|
|
30
|
+
create(request: CreateBotRequest): Promise<BotDto>;
|
|
31
|
+
/**
|
|
32
|
+
* PATCH /api/bots/{id} (dev-only)
|
|
33
|
+
* Update bot metadata. kafkaTopic cannot be changed after creation.
|
|
34
|
+
*/
|
|
35
|
+
update(id: string, request: UpdateBotRequest): Promise<BotDto>;
|
|
36
|
+
/** POST /api/bots/{id}/activate (dev-only) */
|
|
37
|
+
activate(id: string): Promise<void>;
|
|
38
|
+
/** POST /api/bots/{id}/deactivate (dev-only) */
|
|
39
|
+
deactivate(id: string): Promise<void>;
|
|
40
|
+
/** DELETE /api/bots/{id} (dev-only) — soft delete */
|
|
41
|
+
delete(id: string): Promise<void>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=BotApi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotApi.d.ts","sourceRoot":"","sources":["../../src/http/BotApi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD;;;;;;;GAOG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;;OAIG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAQjF,kCAAkC;IAClC,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAIlD;;;OAGG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI9D,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAInC,gDAAgD;IAChD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC,qDAAqD;IACrD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// BotApi.ts — Bot management endpoints
|
|
2
|
+
import { HttpClient } from './HttpClient.js';
|
|
3
|
+
/**
|
|
4
|
+
* Bot API client.
|
|
5
|
+
*
|
|
6
|
+
* GET endpoints (list, getById) are public — no JWT required.
|
|
7
|
+
* Management endpoints (create, update, activate, deactivate, delete)
|
|
8
|
+
* require JWT with claim role=dev (obtained via loginWithDev).
|
|
9
|
+
* Non-dev users receive 404 Not Found on management endpoints.
|
|
10
|
+
*/
|
|
11
|
+
export class BotApi {
|
|
12
|
+
constructor(http) {
|
|
13
|
+
this.http = http;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* GET /api/bots?page={page}&pageSize={pageSize}
|
|
17
|
+
* List all bots (public).
|
|
18
|
+
* page is 1-based.
|
|
19
|
+
*/
|
|
20
|
+
list(params) {
|
|
21
|
+
const qs = new URLSearchParams();
|
|
22
|
+
if (params?.page !== undefined)
|
|
23
|
+
qs.set('page', String(params.page));
|
|
24
|
+
if (params?.pageSize !== undefined)
|
|
25
|
+
qs.set('pageSize', String(params.pageSize));
|
|
26
|
+
const q = qs.toString();
|
|
27
|
+
return this.http.get(`/api/bots${q ? `?${q}` : ''}`);
|
|
28
|
+
}
|
|
29
|
+
/** GET /api/bots/{id} (public) */
|
|
30
|
+
getById(id) {
|
|
31
|
+
return this.http.get(`/api/bots/${encodeURIComponent(id)}`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* POST /api/bots (dev-only)
|
|
35
|
+
* Register a new bot.
|
|
36
|
+
*/
|
|
37
|
+
create(request) {
|
|
38
|
+
return this.http.post('/api/bots', request);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* PATCH /api/bots/{id} (dev-only)
|
|
42
|
+
* Update bot metadata. kafkaTopic cannot be changed after creation.
|
|
43
|
+
*/
|
|
44
|
+
update(id, request) {
|
|
45
|
+
return this.http.patch(`/api/bots/${encodeURIComponent(id)}`, request);
|
|
46
|
+
}
|
|
47
|
+
/** POST /api/bots/{id}/activate (dev-only) */
|
|
48
|
+
activate(id) {
|
|
49
|
+
return this.http.post(`/api/bots/${encodeURIComponent(id)}/activate`);
|
|
50
|
+
}
|
|
51
|
+
/** POST /api/bots/{id}/deactivate (dev-only) */
|
|
52
|
+
deactivate(id) {
|
|
53
|
+
return this.http.post(`/api/bots/${encodeURIComponent(id)}/deactivate`);
|
|
54
|
+
}
|
|
55
|
+
/** DELETE /api/bots/{id} (dev-only) — soft delete */
|
|
56
|
+
delete(id) {
|
|
57
|
+
return this.http.delete(`/api/bots/${encodeURIComponent(id)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=BotApi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotApi.js","sourceRoot":"","sources":["../../src/http/BotApi.ts"],"names":[],"mappings":"AAAA,uCAAuC;AAEvC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAI7C;;;;;;;GAOG;AACH,MAAM,OAAO,MAAM;IAGjB,YAAY,IAAgB;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,IAAI,CAAC,MAA6C;QAChD,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;QACjC,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS;YAAE,EAAE,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,IAAI,MAAM,EAAE,QAAQ,KAAK,SAAS;YAAE,EAAE,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChF,MAAM,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAsB,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,kCAAkC;IAClC,OAAO,CAAC,EAAU;QAChB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAS,aAAa,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAAyB;QAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAS,WAAW,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,EAAU,EAAE,OAAyB;QAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAS,aAAa,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACjF,CAAC;IAED,8CAA8C;IAC9C,QAAQ,CAAC,EAAU;QACjB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAO,aAAa,kBAAkB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAC9E,CAAC;IAED,gDAAgD;IAChD,UAAU,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAO,aAAa,kBAAkB,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAChF,CAAC;IAED,qDAAqD;IACrD,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAO,aAAa,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;CACF"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
import type { ConversationDto, ConversationListItemDto, ConversationMediaItemDto, ConversationMediaKindFilter, ConversationParticipantDto, CreateConversationRequest, UpdateConversationRequest, AddParticipantRequest } from '../types/conversation.js';
|
|
3
|
+
import type { CursorPaginatedResult } from '../types/common.js';
|
|
4
|
+
/**
|
|
5
|
+
* Conversation API client.
|
|
6
|
+
* All endpoints require JWT Bearer token.
|
|
7
|
+
*
|
|
8
|
+
* The system only supports Group conversations (spec §6.2); there is no
|
|
9
|
+
* direct 1-1 or self chat — a conversation with one user and one bot is
|
|
10
|
+
* still modelled as a 2-member Group.
|
|
11
|
+
*/
|
|
12
|
+
export declare class ConversationApi {
|
|
13
|
+
private readonly http;
|
|
14
|
+
constructor(http: HttpClient);
|
|
15
|
+
/**
|
|
16
|
+
* GET /api/conversations?limit={limit}&cursor={cursor}
|
|
17
|
+
*
|
|
18
|
+
* Returns paginated conversations sorted by pinned first (by pinnedAt desc),
|
|
19
|
+
* then by lastMessageAt desc.
|
|
20
|
+
*
|
|
21
|
+
* Each item includes the full lastMessage (MessageDto) for preview. Clients
|
|
22
|
+
* MUST check `lastMessage.isDeleted` before displaying — the aggregator
|
|
23
|
+
* bypasses the deleted-filter (spec §6.1).
|
|
24
|
+
*
|
|
25
|
+
* NOTE: cursor is an opaque composite string "<UnixMs>_<ULID>". Always treat
|
|
26
|
+
* as a string — NEVER cast to number.
|
|
27
|
+
*/
|
|
28
|
+
list(params?: {
|
|
29
|
+
limit?: number;
|
|
30
|
+
cursor?: string;
|
|
31
|
+
}): Promise<CursorPaginatedResult<ConversationListItemDto>>;
|
|
32
|
+
/** POST /api/conversations */
|
|
33
|
+
create(request: CreateConversationRequest): Promise<ConversationDto>;
|
|
34
|
+
/**
|
|
35
|
+
* GET /api/conversations/search?q={query}&limit={limit}
|
|
36
|
+
* Search conversations by name or participant name.
|
|
37
|
+
*/
|
|
38
|
+
search(query: string, limit?: number): Promise<ConversationListItemDto[]>;
|
|
39
|
+
/** GET /api/conversations/{id} */
|
|
40
|
+
getById(id: string): Promise<ConversationDto>;
|
|
41
|
+
/** PATCH /api/conversations/{id} */
|
|
42
|
+
update(id: string, request: UpdateConversationRequest): Promise<ConversationDto>;
|
|
43
|
+
/**
|
|
44
|
+
* DELETE /api/conversations/{id}
|
|
45
|
+
* Alias for {@link leave}: the caller leaves the conversation; other
|
|
46
|
+
* participants keep it (spec §6.7).
|
|
47
|
+
*/
|
|
48
|
+
delete(id: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* POST /api/conversations/{id}/leave
|
|
51
|
+
* Leave the conversation. Identical to {@link delete}; kept as a separate
|
|
52
|
+
* method because the spec exposes both URLs (spec §6.6).
|
|
53
|
+
*/
|
|
54
|
+
leave(id: string): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* POST /api/conversations/{id}/participants
|
|
57
|
+
* Add a participant to the conversation.
|
|
58
|
+
*/
|
|
59
|
+
addParticipant(conversationId: string, request: AddParticipantRequest): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* DELETE /api/conversations/{id}/participants/{participantId}
|
|
62
|
+
* Remove a participant from the conversation.
|
|
63
|
+
*/
|
|
64
|
+
removeParticipant(conversationId: string, participantId: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* GET /api/conversations/{id}/participants
|
|
67
|
+
* Returns all participants (including those who have left).
|
|
68
|
+
*/
|
|
69
|
+
getParticipants(conversationId: string): Promise<ConversationParticipantDto[]>;
|
|
70
|
+
/** POST /api/conversations/{id}/pin */
|
|
71
|
+
pin(id: string): Promise<void>;
|
|
72
|
+
/** DELETE /api/conversations/{id}/pin */
|
|
73
|
+
unpin(id: string): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* GET /api/conversations/{id}/media?kind={kind}&limit={limit}&cursor={cursor}
|
|
76
|
+
*
|
|
77
|
+
* List every media/link item that has appeared in the conversation, newest first.
|
|
78
|
+
*
|
|
79
|
+
* - `kind` — `all` (default), `attachment`, or `link` (case-insensitive on the wire).
|
|
80
|
+
* - `limit` — 1..100, default 50.
|
|
81
|
+
* - `cursor` — opaque `nextCursor` from a prior page.
|
|
82
|
+
*
|
|
83
|
+
* Participants only see items from messages created after they joined the
|
|
84
|
+
* conversation. Returns 403 if the caller is not a participant.
|
|
85
|
+
*/
|
|
86
|
+
getMedia(conversationId: string, params?: {
|
|
87
|
+
kind?: ConversationMediaKindFilter;
|
|
88
|
+
limit?: number;
|
|
89
|
+
cursor?: string;
|
|
90
|
+
}): Promise<CursorPaginatedResult<ConversationMediaItemDto>>;
|
|
91
|
+
}
|
|
92
|
+
//# 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,wBAAwB,EACxB,2BAA2B,EAC3B,0BAA0B,EAC1B,yBAAyB,EACzB,yBAAyB,EACzB,qBAAqB,EACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,MAAM,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,uBAAuB,CAAC,CAAC;IAU3D,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,oCAAoC;IACpC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,eAAe,CAAC;IAIhF;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC;;;OAGG;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;;;;;;;;;;;OAWG;IACH,QAAQ,CACN,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,2BAA2B,CAAC;QACnC,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GACA,OAAO,CAAC,qBAAqB,CAAC,wBAAwB,CAAC,CAAC;CAU5D"}
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
* The system only supports Group conversations (spec §6.2); there is no
|
|
8
|
+
* direct 1-1 or self chat — a conversation with one user and one bot is
|
|
9
|
+
* still modelled as a 2-member Group.
|
|
10
|
+
*/
|
|
11
|
+
export class ConversationApi {
|
|
12
|
+
constructor(http) {
|
|
13
|
+
this.http = http;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* GET /api/conversations?limit={limit}&cursor={cursor}
|
|
17
|
+
*
|
|
18
|
+
* Returns paginated conversations sorted by pinned first (by pinnedAt desc),
|
|
19
|
+
* then by lastMessageAt desc.
|
|
20
|
+
*
|
|
21
|
+
* Each item includes the full lastMessage (MessageDto) for preview. Clients
|
|
22
|
+
* MUST check `lastMessage.isDeleted` before displaying — the aggregator
|
|
23
|
+
* bypasses the deleted-filter (spec §6.1).
|
|
24
|
+
*
|
|
25
|
+
* NOTE: cursor is an opaque composite string "<UnixMs>_<ULID>". Always treat
|
|
26
|
+
* as a string — NEVER cast to number.
|
|
27
|
+
*/
|
|
28
|
+
list(params) {
|
|
29
|
+
const qs = new URLSearchParams();
|
|
30
|
+
if (params?.limit !== undefined)
|
|
31
|
+
qs.set('limit', String(params.limit));
|
|
32
|
+
if (params?.cursor !== undefined)
|
|
33
|
+
qs.set('cursor', params.cursor);
|
|
34
|
+
const q = qs.toString();
|
|
35
|
+
return this.http.get(`/api/conversations${q ? `?${q}` : ''}`);
|
|
36
|
+
}
|
|
37
|
+
/** POST /api/conversations */
|
|
38
|
+
create(request) {
|
|
39
|
+
return this.http.post('/api/conversations', request);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* GET /api/conversations/search?q={query}&limit={limit}
|
|
43
|
+
* Search conversations by name or participant name.
|
|
44
|
+
*/
|
|
45
|
+
search(query, limit) {
|
|
46
|
+
const qs = new URLSearchParams({ q: query });
|
|
47
|
+
if (limit !== undefined)
|
|
48
|
+
qs.set('limit', String(limit));
|
|
49
|
+
return this.http.get(`/api/conversations/search?${qs.toString()}`);
|
|
50
|
+
}
|
|
51
|
+
/** GET /api/conversations/{id} */
|
|
52
|
+
getById(id) {
|
|
53
|
+
return this.http.get(`/api/conversations/${encodeURIComponent(id)}`);
|
|
54
|
+
}
|
|
55
|
+
/** PATCH /api/conversations/{id} */
|
|
56
|
+
update(id, request) {
|
|
57
|
+
return this.http.patch(`/api/conversations/${encodeURIComponent(id)}`, request);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* DELETE /api/conversations/{id}
|
|
61
|
+
* Alias for {@link leave}: the caller leaves the conversation; other
|
|
62
|
+
* participants keep it (spec §6.7).
|
|
63
|
+
*/
|
|
64
|
+
delete(id) {
|
|
65
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(id)}`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* POST /api/conversations/{id}/leave
|
|
69
|
+
* Leave the conversation. Identical to {@link delete}; kept as a separate
|
|
70
|
+
* method because the spec exposes both URLs (spec §6.6).
|
|
71
|
+
*/
|
|
72
|
+
leave(id) {
|
|
73
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(id)}/leave`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* POST /api/conversations/{id}/participants
|
|
77
|
+
* Add a participant to the conversation.
|
|
78
|
+
*/
|
|
79
|
+
addParticipant(conversationId, request) {
|
|
80
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(conversationId)}/participants`, request);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* DELETE /api/conversations/{id}/participants/{participantId}
|
|
84
|
+
* Remove a participant from the conversation.
|
|
85
|
+
*/
|
|
86
|
+
removeParticipant(conversationId, participantId) {
|
|
87
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(conversationId)}/participants/${encodeURIComponent(participantId)}`);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* GET /api/conversations/{id}/participants
|
|
91
|
+
* Returns all participants (including those who have left).
|
|
92
|
+
*/
|
|
93
|
+
getParticipants(conversationId) {
|
|
94
|
+
return this.http.get(`/api/conversations/${encodeURIComponent(conversationId)}/participants`);
|
|
95
|
+
}
|
|
96
|
+
/** POST /api/conversations/{id}/pin */
|
|
97
|
+
pin(id) {
|
|
98
|
+
return this.http.post(`/api/conversations/${encodeURIComponent(id)}/pin`);
|
|
99
|
+
}
|
|
100
|
+
/** DELETE /api/conversations/{id}/pin */
|
|
101
|
+
unpin(id) {
|
|
102
|
+
return this.http.delete(`/api/conversations/${encodeURIComponent(id)}/pin`);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* GET /api/conversations/{id}/media?kind={kind}&limit={limit}&cursor={cursor}
|
|
106
|
+
*
|
|
107
|
+
* List every media/link item that has appeared in the conversation, newest first.
|
|
108
|
+
*
|
|
109
|
+
* - `kind` — `all` (default), `attachment`, or `link` (case-insensitive on the wire).
|
|
110
|
+
* - `limit` — 1..100, default 50.
|
|
111
|
+
* - `cursor` — opaque `nextCursor` from a prior page.
|
|
112
|
+
*
|
|
113
|
+
* Participants only see items from messages created after they joined the
|
|
114
|
+
* conversation. Returns 403 if the caller is not a participant.
|
|
115
|
+
*/
|
|
116
|
+
getMedia(conversationId, params) {
|
|
117
|
+
const qs = new URLSearchParams();
|
|
118
|
+
if (params?.kind !== undefined)
|
|
119
|
+
qs.set('kind', params.kind);
|
|
120
|
+
if (params?.limit !== undefined)
|
|
121
|
+
qs.set('limit', String(params.limit));
|
|
122
|
+
if (params?.cursor !== undefined)
|
|
123
|
+
qs.set('cursor', params.cursor);
|
|
124
|
+
const q = qs.toString();
|
|
125
|
+
return this.http.get(`/api/conversations/${encodeURIComponent(conversationId)}/media${q ? `?${q}` : ''}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# 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,60 @@
|
|
|
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
|
+
*
|
|
32
|
+
* Default download is public — no auth required:
|
|
33
|
+
* getDownloadUrl("01HXABCDEF/photo.jpg")
|
|
34
|
+
* → "{baseUrl}/api/files/01HXABCDEF/photo.jpg"
|
|
35
|
+
*
|
|
36
|
+
* Pass `signed` to build a signed URL (spec §8.3) when the server enforces
|
|
37
|
+
* controlled access. Both `expires` and `sig` must be supplied — typically
|
|
38
|
+
* forwarded from the upload-url response or another server-issued source.
|
|
39
|
+
* Server returns 400 Bad Request (title `Invalid Signature`) if the URL has
|
|
40
|
+
* been tampered with or has expired.
|
|
41
|
+
*/
|
|
42
|
+
getDownloadUrl(storageKey: string, signed?: {
|
|
43
|
+
expires: string;
|
|
44
|
+
sig: string;
|
|
45
|
+
}): string;
|
|
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") — `/`
|
|
50
|
+
* is preserved as a path delimiter; other special characters are percent-encoded.
|
|
51
|
+
*/
|
|
52
|
+
delete(storageKey: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Convenience method: create upload URL then immediately upload the file.
|
|
55
|
+
* Equivalent to calling createUploadUrl() + upload() in sequence.
|
|
56
|
+
* onProgress is forwarded to the upload step.
|
|
57
|
+
*/
|
|
58
|
+
uploadFile(file: File, onProgress?: UploadProgressCallback): Promise<UploadResponse>;
|
|
59
|
+
}
|
|
60
|
+
//# 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;;;;;;;;;;;;OAYG;IACH,cAAc,CACZ,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GACxC,MAAM;IAOT;;;;;OAKG;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,91 @@
|
|
|
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
|
+
*
|
|
41
|
+
* Default download is public — no auth required:
|
|
42
|
+
* getDownloadUrl("01HXABCDEF/photo.jpg")
|
|
43
|
+
* → "{baseUrl}/api/files/01HXABCDEF/photo.jpg"
|
|
44
|
+
*
|
|
45
|
+
* Pass `signed` to build a signed URL (spec §8.3) when the server enforces
|
|
46
|
+
* controlled access. Both `expires` and `sig` must be supplied — typically
|
|
47
|
+
* forwarded from the upload-url response or another server-issued source.
|
|
48
|
+
* Server returns 400 Bad Request (title `Invalid Signature`) if the URL has
|
|
49
|
+
* been tampered with or has expired.
|
|
50
|
+
*/
|
|
51
|
+
getDownloadUrl(storageKey, signed) {
|
|
52
|
+
const path = `/api/files/${encodeStorageKeyPath(storageKey)}`;
|
|
53
|
+
if (!signed)
|
|
54
|
+
return `${this.http.baseUrl}${path}`;
|
|
55
|
+
const qs = new URLSearchParams({ expires: signed.expires, sig: signed.sig });
|
|
56
|
+
return `${this.http.baseUrl}${path}?${qs.toString()}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* DELETE /api/files/{storageKey}
|
|
60
|
+
* Delete an uploaded file. Only the uploader can delete.
|
|
61
|
+
* storageKey may contain path separators (e.g. "01HXABCDEF/photo.jpg") — `/`
|
|
62
|
+
* is preserved as a path delimiter; other special characters are percent-encoded.
|
|
63
|
+
*/
|
|
64
|
+
delete(storageKey) {
|
|
65
|
+
return this.http.delete(`/api/files/${encodeStorageKeyPath(storageKey)}`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Convenience method: create upload URL then immediately upload the file.
|
|
69
|
+
* Equivalent to calling createUploadUrl() + upload() in sequence.
|
|
70
|
+
* onProgress is forwarded to the upload step.
|
|
71
|
+
*/
|
|
72
|
+
async uploadFile(file, onProgress) {
|
|
73
|
+
const { uploadUrl } = await this.createUploadUrl({
|
|
74
|
+
fileName: file.name,
|
|
75
|
+
contentType: file.type,
|
|
76
|
+
fileSize: file.size,
|
|
77
|
+
});
|
|
78
|
+
return this.upload(uploadUrl, file, onProgress);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Percent-encode each segment of a storage key while preserving `/` as the
|
|
83
|
+
* path separator. The server's catch-all route accepts the unencoded key it
|
|
84
|
+
* generated, but a key containing characters like spaces, `?`, `#`, or `%`
|
|
85
|
+
* would otherwise corrupt the URL. Pure pass-through (the previous behaviour)
|
|
86
|
+
* is preserved for the common case where keys are ULID/filename-safe.
|
|
87
|
+
*/
|
|
88
|
+
function encodeStorageKeyPath(storageKey) {
|
|
89
|
+
return storageKey.split('/').map(encodeURIComponent).join('/');
|
|
90
|
+
}
|
|
91
|
+
//# 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;;;;;;;;;;;;OAYG;IACH,cAAc,CACZ,UAAkB,EAClB,MAAyC;QAEzC,MAAM,IAAI,GAAG,cAAc,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC;QAClD,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;QAC7E,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;IACxD,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,UAAkB;QACvB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAO,cAAc,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClF,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;AAED;;;;;;GAMG;AACH,SAAS,oBAAoB,CAAC,UAAkB;IAC9C,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACjE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { HttpClient } from './HttpClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* Health check API client.
|
|
4
|
+
* All endpoints are public — no JWT required.
|
|
5
|
+
*
|
|
6
|
+
* Both endpoints return `text/plain` ("Healthy" / "Degraded" / "Unhealthy"),
|
|
7
|
+
* NOT JSON — the server uses ASP.NET Health Checks' default ResponseWriter.
|
|
8
|
+
*/
|
|
9
|
+
export declare class HealthApi {
|
|
10
|
+
private readonly http;
|
|
11
|
+
constructor(http: HttpClient);
|
|
12
|
+
/**
|
|
13
|
+
* GET /health/live
|
|
14
|
+
* Liveness probe — returns the plain text string "Healthy" when the server is up.
|
|
15
|
+
*/
|
|
16
|
+
live(): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* GET /health/ready
|
|
19
|
+
* Readiness probe — returns plain text "Healthy" / "Degraded" / "Unhealthy".
|
|
20
|
+
* HTTP status: 200 when Healthy/Degraded, 503 when Unhealthy.
|
|
21
|
+
*
|
|
22
|
+
* Note: the gateway is stateless and registers no checks tagged `ready`, so
|
|
23
|
+
* this currently always returns "Healthy". Call the backend's own
|
|
24
|
+
* `/health/ready` if you need infrastructure readiness.
|
|
25
|
+
*/
|
|
26
|
+
ready(): Promise<string>;
|
|
27
|
+
}
|
|
28
|
+
//# 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;AAE7C;;;;;;GAMG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;gBAEtB,IAAI,EAAE,UAAU;IAI5B;;;OAGG;IACH,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvB;;;;;;;;OAQG;IACH,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;CAGzB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
* Both endpoints return `text/plain` ("Healthy" / "Degraded" / "Unhealthy"),
|
|
8
|
+
* NOT JSON — the server uses ASP.NET Health Checks' default ResponseWriter.
|
|
9
|
+
*/
|
|
10
|
+
export class HealthApi {
|
|
11
|
+
constructor(http) {
|
|
12
|
+
this.http = http;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* GET /health/live
|
|
16
|
+
* Liveness probe — returns the plain text string "Healthy" when the server is up.
|
|
17
|
+
*/
|
|
18
|
+
live() {
|
|
19
|
+
return this.http.getText('/health/live');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* GET /health/ready
|
|
23
|
+
* Readiness probe — returns plain text "Healthy" / "Degraded" / "Unhealthy".
|
|
24
|
+
* HTTP status: 200 when Healthy/Degraded, 503 when Unhealthy.
|
|
25
|
+
*
|
|
26
|
+
* Note: the gateway is stateless and registers no checks tagged `ready`, so
|
|
27
|
+
* this currently always returns "Healthy". Call the backend's own
|
|
28
|
+
* `/health/ready` if you need infrastructure readiness.
|
|
29
|
+
*/
|
|
30
|
+
ready() {
|
|
31
|
+
return this.http.getText('/health/ready');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
//# 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;AAE7C;;;;;;GAMG;AACH,MAAM,OAAO,SAAS;IAGpB,YAAY,IAAgB;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK;QACH,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC5C,CAAC;CACF"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { UploadProgressCallback } from '../types/common.js';
|
|
2
|
+
/** Default per-request timeout (ms) when none is supplied. */
|
|
3
|
+
export declare const DEFAULT_REQUEST_TIMEOUT_MS = 30000;
|
|
4
|
+
export interface HttpClientOptions {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Returns the current JWT token, or null if not authenticated */
|
|
7
|
+
tokenProvider?: () => string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Per-request timeout in milliseconds. Default 30000.
|
|
10
|
+
* Pass `null` to disable the timeout (uploads of large files may need this).
|
|
11
|
+
*/
|
|
12
|
+
requestTimeoutMs?: number | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Base HTTP client wrapping the Fetch API.
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Automatic Authorization: Bearer token injection via tokenProvider
|
|
19
|
+
* - JSON request/response serialization
|
|
20
|
+
* - Throws ChatApiError on non-OK responses
|
|
21
|
+
* - Handles empty responses (204 No Content, 200 with no body) — the SDK
|
|
22
|
+
* convention is to type T as `null` or `void` for empty-body endpoints
|
|
23
|
+
* - Multipart file upload with optional XHR-based upload progress
|
|
24
|
+
* - Per-request timeout via AbortController (configurable, default 30s)
|
|
25
|
+
*/
|
|
26
|
+
export declare class HttpClient {
|
|
27
|
+
readonly baseUrl: string;
|
|
28
|
+
private readonly tokenProvider;
|
|
29
|
+
private readonly requestTimeoutMs;
|
|
30
|
+
constructor(options: HttpClientOptions);
|
|
31
|
+
private buildUrl;
|
|
32
|
+
private buildHeaders;
|
|
33
|
+
private buildAuthHeader;
|
|
34
|
+
/**
|
|
35
|
+
* Parse response body safely.
|
|
36
|
+
* Returns null for 204 No Content or empty bodies.
|
|
37
|
+
* Wraps JSON parse failures in ChatApiError for consistency with the XHR path.
|
|
38
|
+
*/
|
|
39
|
+
private parseBody;
|
|
40
|
+
private handleResponse;
|
|
41
|
+
/**
|
|
42
|
+
* Run a fetch with an AbortController-based timeout.
|
|
43
|
+
* Throws ChatApiError(0, 'Timeout', ...) when the timeout fires before the
|
|
44
|
+
* response arrives. If `requestTimeoutMs` is null, fetch is used directly.
|
|
45
|
+
*/
|
|
46
|
+
private fetchWithTimeout;
|
|
47
|
+
get<T>(path: string, headers?: Record<string, string>): Promise<T>;
|
|
48
|
+
/**
|
|
49
|
+
* GET a plain-text response (e.g. /health/live which returns "Healthy").
|
|
50
|
+
* Unlike get<T>(), this does not attempt JSON parsing.
|
|
51
|
+
*/
|
|
52
|
+
getText(path: string): Promise<string>;
|
|
53
|
+
post<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
54
|
+
patch<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
55
|
+
put<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
56
|
+
delete<T>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
57
|
+
/**
|
|
58
|
+
* POST with multipart/form-data — no explicit Content-Type header
|
|
59
|
+
* (browser sets it with the boundary automatically).
|
|
60
|
+
*/
|
|
61
|
+
postFormData<T>(path: string, formData: FormData): Promise<T>;
|
|
62
|
+
/**
|
|
63
|
+
* POST with multipart/form-data and upload progress reporting.
|
|
64
|
+
* Uses XMLHttpRequest instead of fetch because fetch does not support
|
|
65
|
+
* upload progress events.
|
|
66
|
+
*/
|
|
67
|
+
postFormDataWithProgress<T>(path: string, formData: FormData, onProgress?: UploadProgressCallback): Promise<T>;
|
|
68
|
+
}
|
|
69
|
+
//# 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,8DAA8D;AAC9D,eAAO,MAAM,0BAA0B,QAAS,CAAC;AAEjD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACpC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgB;gBAErC,OAAO,EAAE,iBAAiB;IAYtC,OAAO,CAAC,QAAQ;IAUhB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,eAAe;IAQvB;;;;OAIG;YACW,SAAS;YAaT,cAAc;IAW5B;;;;OAIG;YACW,gBAAgB;IA6BxB,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,GAAG,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;IASlF,MAAM,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;IAW3F;;;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;CA2Dd"}
|