@appthen/sdk-web 0.0.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/dist/index.d.ts +90 -0
- package/dist/index.js +396 -0
- package/package.json +33 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @appthen/sdk-web
|
|
3
|
+
*
|
|
4
|
+
* V0 Web 适配:
|
|
5
|
+
* - HttpAdapter: fetch
|
|
6
|
+
* - AuthProvider: localStorage / memory
|
|
7
|
+
* - RealtimeAdapter: socket.io conversation room adapter
|
|
8
|
+
*/
|
|
9
|
+
import { ChatHubClient, type AuthProvider, type HttpAdapter, type HttpRequestOptions, type HttpResponse, type RealtimeAdapter, type RealtimeSubscription } from '@appthen/sdk-core';
|
|
10
|
+
export { SDK_VERSION } from '@appthen/sdk-core';
|
|
11
|
+
export * from '@appthen/sdk-core';
|
|
12
|
+
export declare class FetchHttpAdapter implements HttpAdapter {
|
|
13
|
+
private readonly baseUrl;
|
|
14
|
+
constructor(baseUrl: string);
|
|
15
|
+
request<T>(options: HttpRequestOptions): Promise<HttpResponse<T>>;
|
|
16
|
+
}
|
|
17
|
+
export declare class LocalStorageAuthProvider implements AuthProvider {
|
|
18
|
+
private readonly storageKey;
|
|
19
|
+
constructor(storageKey?: string);
|
|
20
|
+
getToken(): Promise<string | null>;
|
|
21
|
+
setToken(token: string | null): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export declare class MemoryAuthProvider implements AuthProvider {
|
|
24
|
+
private token;
|
|
25
|
+
constructor(token?: string | null);
|
|
26
|
+
getToken(): Promise<string | null>;
|
|
27
|
+
setToken(token: string | null): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
export declare class NoopRealtimeAdapter implements RealtimeAdapter {
|
|
30
|
+
connect(): Promise<void>;
|
|
31
|
+
disconnect(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
export interface ConversationSocketEvent {
|
|
34
|
+
eventName?: string;
|
|
35
|
+
room?: string;
|
|
36
|
+
conversationId?: string;
|
|
37
|
+
message?: unknown;
|
|
38
|
+
userId?: string;
|
|
39
|
+
participants?: string[];
|
|
40
|
+
participantCount?: number;
|
|
41
|
+
isTyping?: boolean;
|
|
42
|
+
senderSubjectId?: string;
|
|
43
|
+
messageId?: string;
|
|
44
|
+
readAt?: string;
|
|
45
|
+
[key: string]: unknown;
|
|
46
|
+
}
|
|
47
|
+
export interface SocketIoConversationRealtimeAdapterOptions {
|
|
48
|
+
url: string;
|
|
49
|
+
account?: () => string | null | Promise<string | null>;
|
|
50
|
+
roomPrefix?: string;
|
|
51
|
+
eventName?: string;
|
|
52
|
+
}
|
|
53
|
+
export declare class SocketIoConversationRealtimeAdapter implements RealtimeAdapter {
|
|
54
|
+
private readonly options;
|
|
55
|
+
private socket;
|
|
56
|
+
private connectPromise;
|
|
57
|
+
private activeRooms;
|
|
58
|
+
private subscriptions;
|
|
59
|
+
private globalListeners;
|
|
60
|
+
constructor(options: SocketIoConversationRealtimeAdapterOptions);
|
|
61
|
+
private get roomPrefix();
|
|
62
|
+
private get messageEventName();
|
|
63
|
+
private getConversationRoom;
|
|
64
|
+
private getAccount;
|
|
65
|
+
private ensureSocket;
|
|
66
|
+
private emitJoin;
|
|
67
|
+
private emitLeave;
|
|
68
|
+
private joinActiveRooms;
|
|
69
|
+
connect(token?: string | null): Promise<void>;
|
|
70
|
+
disconnect(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* 加入任意房间(如跨设备同步用的同主体设备房间)。纳入 activeRooms 引用计数,
|
|
73
|
+
* 断线重连时会自动重新加入。
|
|
74
|
+
*/
|
|
75
|
+
joinRoom(room: string): Promise<void>;
|
|
76
|
+
leaveRoom(room: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* 注册全局 socket 事件监听(所有房间均会转发),返回退订函数。
|
|
79
|
+
* 用于接收跨设备同步等非会话作用域的事件。
|
|
80
|
+
*/
|
|
81
|
+
onGlobalEvent(handler: (event: Record<string, unknown>) => void): () => void;
|
|
82
|
+
subscribeConversation(conversationId: string): Promise<RealtimeSubscription<ConversationSocketEvent>>;
|
|
83
|
+
publishConversationEvent(conversationId: string, event: Record<string, unknown>): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
export interface CreateWebChatHubClientOptions {
|
|
86
|
+
baseUrl: string;
|
|
87
|
+
auth?: AuthProvider;
|
|
88
|
+
realtime?: RealtimeAdapter;
|
|
89
|
+
}
|
|
90
|
+
export declare function createChatHubClient(options: CreateWebChatHubClientOptions): ChatHubClient;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @appthen/sdk-web
|
|
3
|
+
*
|
|
4
|
+
* V0 Web 适配:
|
|
5
|
+
* - HttpAdapter: fetch
|
|
6
|
+
* - AuthProvider: localStorage / memory
|
|
7
|
+
* - RealtimeAdapter: socket.io conversation room adapter
|
|
8
|
+
*/
|
|
9
|
+
import { io } from 'socket.io-client';
|
|
10
|
+
import { ChatHubClient, } from '@appthen/sdk-core';
|
|
11
|
+
export { SDK_VERSION } from '@appthen/sdk-core';
|
|
12
|
+
export * from '@appthen/sdk-core';
|
|
13
|
+
function joinUrl(baseUrl, path) {
|
|
14
|
+
if (/^https?:\/\//.test(path)) {
|
|
15
|
+
return path;
|
|
16
|
+
}
|
|
17
|
+
const normalizedBase = baseUrl.replace(/\/+$/, '');
|
|
18
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
19
|
+
return `${normalizedBase}${normalizedPath}`;
|
|
20
|
+
}
|
|
21
|
+
function appendQuery(url, query) {
|
|
22
|
+
if (!query) {
|
|
23
|
+
return url;
|
|
24
|
+
}
|
|
25
|
+
const params = new URLSearchParams();
|
|
26
|
+
Object.entries(query).forEach(([key, value]) => {
|
|
27
|
+
if (value === undefined) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
params.set(key, String(value));
|
|
31
|
+
});
|
|
32
|
+
const serialized = params.toString();
|
|
33
|
+
return serialized ? `${url}?${serialized}` : url;
|
|
34
|
+
}
|
|
35
|
+
function isJsonResponse(contentType) {
|
|
36
|
+
return typeof contentType === 'string' && contentType.includes('application/json');
|
|
37
|
+
}
|
|
38
|
+
export class FetchHttpAdapter {
|
|
39
|
+
constructor(baseUrl) {
|
|
40
|
+
this.baseUrl = baseUrl;
|
|
41
|
+
}
|
|
42
|
+
async request(options) {
|
|
43
|
+
const url = appendQuery(joinUrl(this.baseUrl, options.path), options.query);
|
|
44
|
+
const response = await fetch(url, {
|
|
45
|
+
method: options.method,
|
|
46
|
+
headers: {
|
|
47
|
+
...(options.body ? { 'Content-Type': 'application/json' } : {}),
|
|
48
|
+
...(options.headers || {}),
|
|
49
|
+
},
|
|
50
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
51
|
+
});
|
|
52
|
+
const contentType = response.headers.get('content-type');
|
|
53
|
+
const data = isJsonResponse(contentType)
|
|
54
|
+
? (await response.json())
|
|
55
|
+
: (await response.text());
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const error = new Error(`HTTP ${response.status} for ${options.method} ${options.path}`);
|
|
58
|
+
error.response = data;
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
const headers = {};
|
|
62
|
+
response.headers.forEach((value, key) => {
|
|
63
|
+
headers[key] = value;
|
|
64
|
+
});
|
|
65
|
+
return {
|
|
66
|
+
status: response.status,
|
|
67
|
+
data,
|
|
68
|
+
headers,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export class LocalStorageAuthProvider {
|
|
73
|
+
constructor(storageKey = 'chat-hub:token') {
|
|
74
|
+
this.storageKey = storageKey;
|
|
75
|
+
}
|
|
76
|
+
async getToken() {
|
|
77
|
+
if (typeof globalThis.localStorage === 'undefined') {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return globalThis.localStorage.getItem(this.storageKey);
|
|
81
|
+
}
|
|
82
|
+
async setToken(token) {
|
|
83
|
+
if (typeof globalThis.localStorage === 'undefined') {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (token) {
|
|
87
|
+
globalThis.localStorage.setItem(this.storageKey, token);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
globalThis.localStorage.removeItem(this.storageKey);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export class MemoryAuthProvider {
|
|
95
|
+
constructor(token = null) {
|
|
96
|
+
this.token = token;
|
|
97
|
+
}
|
|
98
|
+
async getToken() {
|
|
99
|
+
return this.token;
|
|
100
|
+
}
|
|
101
|
+
async setToken(token) {
|
|
102
|
+
this.token = token;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export class NoopRealtimeAdapter {
|
|
106
|
+
async connect() {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
async disconnect() {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
class SocketConversationSubscription {
|
|
114
|
+
constructor(onClose) {
|
|
115
|
+
this.onClose = onClose;
|
|
116
|
+
this.queue = [];
|
|
117
|
+
this.waiters = [];
|
|
118
|
+
this.closed = false;
|
|
119
|
+
}
|
|
120
|
+
push(event) {
|
|
121
|
+
if (this.closed) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const waiter = this.waiters.shift();
|
|
125
|
+
if (waiter) {
|
|
126
|
+
waiter({ value: event, done: false });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.queue.push(event);
|
|
130
|
+
}
|
|
131
|
+
async close() {
|
|
132
|
+
if (this.closed) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.closed = true;
|
|
136
|
+
await this.onClose();
|
|
137
|
+
while (this.waiters.length > 0) {
|
|
138
|
+
const waiter = this.waiters.shift();
|
|
139
|
+
waiter?.({ value: undefined, done: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
[Symbol.asyncIterator]() {
|
|
143
|
+
return {
|
|
144
|
+
next: async () => {
|
|
145
|
+
if (this.queue.length > 0) {
|
|
146
|
+
return {
|
|
147
|
+
value: this.queue.shift(),
|
|
148
|
+
done: false,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (this.closed) {
|
|
152
|
+
return {
|
|
153
|
+
value: undefined,
|
|
154
|
+
done: true,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return new Promise((resolve) => {
|
|
158
|
+
this.waiters.push(resolve);
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
return: async () => {
|
|
162
|
+
await this.close();
|
|
163
|
+
return {
|
|
164
|
+
value: undefined,
|
|
165
|
+
done: true,
|
|
166
|
+
};
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export class SocketIoConversationRealtimeAdapter {
|
|
172
|
+
constructor(options) {
|
|
173
|
+
this.options = options;
|
|
174
|
+
this.socket = null;
|
|
175
|
+
this.connectPromise = null;
|
|
176
|
+
this.activeRooms = new Map();
|
|
177
|
+
this.subscriptions = new Map();
|
|
178
|
+
this.globalListeners = new Set();
|
|
179
|
+
}
|
|
180
|
+
get roomPrefix() {
|
|
181
|
+
return this.options.roomPrefix || 'hub:conversation:';
|
|
182
|
+
}
|
|
183
|
+
get messageEventName() {
|
|
184
|
+
return this.options.eventName || 'message';
|
|
185
|
+
}
|
|
186
|
+
getConversationRoom(conversationId) {
|
|
187
|
+
return `${this.roomPrefix}${conversationId}`;
|
|
188
|
+
}
|
|
189
|
+
async getAccount() {
|
|
190
|
+
return (await this.options.account?.()) || 'anonymous';
|
|
191
|
+
}
|
|
192
|
+
async ensureSocket(token) {
|
|
193
|
+
if (this.socket?.connected) {
|
|
194
|
+
return this.socket;
|
|
195
|
+
}
|
|
196
|
+
if (this.connectPromise) {
|
|
197
|
+
await this.connectPromise;
|
|
198
|
+
return this.socket;
|
|
199
|
+
}
|
|
200
|
+
this.connectPromise = new Promise((resolve, reject) => {
|
|
201
|
+
const socket = io(this.options.url, {
|
|
202
|
+
autoConnect: false,
|
|
203
|
+
transports: ['websocket'],
|
|
204
|
+
query: token ? { token } : {},
|
|
205
|
+
});
|
|
206
|
+
const cleanup = () => {
|
|
207
|
+
socket.off('connect', handleConnect);
|
|
208
|
+
socket.off('connect_error', handleError);
|
|
209
|
+
};
|
|
210
|
+
const handleConnect = async () => {
|
|
211
|
+
cleanup();
|
|
212
|
+
this.socket = socket;
|
|
213
|
+
socket.on(this.messageEventName, (payload) => {
|
|
214
|
+
const evtName = payload && typeof payload === 'object'
|
|
215
|
+
? payload.eventName
|
|
216
|
+
: undefined;
|
|
217
|
+
if (typeof console !== 'undefined') {
|
|
218
|
+
console.info('[chat-hub-realtime] message event', String(evtName || '?'), payload?.room || '');
|
|
219
|
+
}
|
|
220
|
+
this.globalListeners.forEach((listener) => listener(payload));
|
|
221
|
+
const room = payload?.room;
|
|
222
|
+
if (!room) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const roomSubscriptions = this.subscriptions.get(room);
|
|
226
|
+
if (!roomSubscriptions || roomSubscriptions.size === 0) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
roomSubscriptions.forEach((subscription) => {
|
|
230
|
+
subscription.push(payload);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
socket.on('connect', async () => {
|
|
234
|
+
await this.joinActiveRooms();
|
|
235
|
+
});
|
|
236
|
+
await this.joinActiveRooms();
|
|
237
|
+
resolve();
|
|
238
|
+
};
|
|
239
|
+
const handleError = (error) => {
|
|
240
|
+
cleanup();
|
|
241
|
+
socket.close();
|
|
242
|
+
reject(error);
|
|
243
|
+
};
|
|
244
|
+
socket.once('connect', handleConnect);
|
|
245
|
+
socket.once('connect_error', handleError);
|
|
246
|
+
socket.connect();
|
|
247
|
+
});
|
|
248
|
+
try {
|
|
249
|
+
await this.connectPromise;
|
|
250
|
+
}
|
|
251
|
+
finally {
|
|
252
|
+
this.connectPromise = null;
|
|
253
|
+
}
|
|
254
|
+
return this.socket;
|
|
255
|
+
}
|
|
256
|
+
async emitJoin(room) {
|
|
257
|
+
const socket = this.socket;
|
|
258
|
+
if (!socket?.connected) {
|
|
259
|
+
// 连接未就绪时等待就绪后再 join,避免静默跳过导致收不到房间事件
|
|
260
|
+
try {
|
|
261
|
+
await this.ensureSocket();
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
const readySocket = this.socket;
|
|
267
|
+
if (!readySocket?.connected) {
|
|
268
|
+
if (typeof console !== 'undefined') {
|
|
269
|
+
console.warn('[chat-hub-realtime] join skipped: socket not connected', room);
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
readySocket.emit('join', {
|
|
274
|
+
room,
|
|
275
|
+
account: await this.getAccount(),
|
|
276
|
+
});
|
|
277
|
+
if (typeof console !== 'undefined') {
|
|
278
|
+
console.info('[chat-hub-realtime] joined room', room);
|
|
279
|
+
}
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
socket.emit('join', {
|
|
283
|
+
room,
|
|
284
|
+
account: await this.getAccount(),
|
|
285
|
+
});
|
|
286
|
+
if (typeof console !== 'undefined') {
|
|
287
|
+
console.info('[chat-hub-realtime] joined room', room);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async emitLeave(room) {
|
|
291
|
+
const socket = this.socket;
|
|
292
|
+
if (!socket?.connected) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
socket.emit('leave', {
|
|
296
|
+
room,
|
|
297
|
+
account: await this.getAccount(),
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
async joinActiveRooms() {
|
|
301
|
+
await Promise.all(Array.from(this.activeRooms.keys()).map((room) => this.emitJoin(room)));
|
|
302
|
+
}
|
|
303
|
+
async connect(token) {
|
|
304
|
+
await this.ensureSocket(token);
|
|
305
|
+
}
|
|
306
|
+
async disconnect() {
|
|
307
|
+
const socket = this.socket;
|
|
308
|
+
this.socket = null;
|
|
309
|
+
this.connectPromise = null;
|
|
310
|
+
this.globalListeners.clear();
|
|
311
|
+
if (socket) {
|
|
312
|
+
socket.removeAllListeners();
|
|
313
|
+
socket.disconnect();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* 加入任意房间(如跨设备同步用的同主体设备房间)。纳入 activeRooms 引用计数,
|
|
318
|
+
* 断线重连时会自动重新加入。
|
|
319
|
+
*/
|
|
320
|
+
async joinRoom(room) {
|
|
321
|
+
await this.ensureSocket();
|
|
322
|
+
const current = this.activeRooms.get(room) || 0;
|
|
323
|
+
this.activeRooms.set(room, current + 1);
|
|
324
|
+
if (current === 0) {
|
|
325
|
+
await this.emitJoin(room);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async leaveRoom(room) {
|
|
329
|
+
const current = this.activeRooms.get(room) || 0;
|
|
330
|
+
const next = Math.max(current - 1, 0);
|
|
331
|
+
if (next === 0) {
|
|
332
|
+
this.activeRooms.delete(room);
|
|
333
|
+
await this.emitLeave(room);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
this.activeRooms.set(room, next);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* 注册全局 socket 事件监听(所有房间均会转发),返回退订函数。
|
|
341
|
+
* 用于接收跨设备同步等非会话作用域的事件。
|
|
342
|
+
*/
|
|
343
|
+
onGlobalEvent(handler) {
|
|
344
|
+
this.globalListeners.add(handler);
|
|
345
|
+
return () => {
|
|
346
|
+
this.globalListeners.delete(handler);
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
async subscribeConversation(conversationId) {
|
|
350
|
+
await this.ensureSocket();
|
|
351
|
+
const room = this.getConversationRoom(conversationId);
|
|
352
|
+
const currentRefCount = this.activeRooms.get(room) || 0;
|
|
353
|
+
this.activeRooms.set(room, currentRefCount + 1);
|
|
354
|
+
// 每次订阅都显式 join(socket.join 幂等):避免"此前 join 过 → 计数非 0 跳过 join"
|
|
355
|
+
// 导致 socket 重连后不在房间、收不到事件的历史遗留坑。
|
|
356
|
+
await this.emitJoin(room);
|
|
357
|
+
const subscription = new SocketConversationSubscription(async () => {
|
|
358
|
+
const roomSubscriptions = this.subscriptions.get(room);
|
|
359
|
+
roomSubscriptions?.delete(subscription);
|
|
360
|
+
if (roomSubscriptions && roomSubscriptions.size === 0) {
|
|
361
|
+
this.subscriptions.delete(room);
|
|
362
|
+
}
|
|
363
|
+
const nextRefCount = Math.max((this.activeRooms.get(room) || 1) - 1, 0);
|
|
364
|
+
if (nextRefCount === 0) {
|
|
365
|
+
this.activeRooms.delete(room);
|
|
366
|
+
await this.leaveRoom(room);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.activeRooms.set(room, nextRefCount);
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
const roomSubscriptions = this.subscriptions.get(room) || new Set();
|
|
373
|
+
roomSubscriptions.add(subscription);
|
|
374
|
+
this.subscriptions.set(room, roomSubscriptions);
|
|
375
|
+
return subscription;
|
|
376
|
+
}
|
|
377
|
+
async publishConversationEvent(conversationId, event) {
|
|
378
|
+
const socket = await this.ensureSocket();
|
|
379
|
+
const account = await this.getAccount();
|
|
380
|
+
const room = this.getConversationRoom(conversationId);
|
|
381
|
+
socket?.emit('message', {
|
|
382
|
+
room,
|
|
383
|
+
conversationId,
|
|
384
|
+
userId: account,
|
|
385
|
+
...event,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
export function createChatHubClient(options) {
|
|
390
|
+
const clientOptions = {
|
|
391
|
+
http: new FetchHttpAdapter(options.baseUrl),
|
|
392
|
+
auth: options.auth || new LocalStorageAuthProvider(),
|
|
393
|
+
realtime: options.realtime || new NoopRealtimeAdapter(),
|
|
394
|
+
};
|
|
395
|
+
return new ChatHubClient(clientOptions);
|
|
396
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appthen/sdk-web",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "AppThen Conversation Hub SDK - Web platform adapter (fetch + socket.io-client)",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@appthen/sdk-core": "0.0.0"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"socket.io-client": "^4.7.0"
|
|
24
|
+
},
|
|
25
|
+
"sideEffects": false,
|
|
26
|
+
"license": "UNLICENSED",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc -p tsconfig.json",
|
|
29
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
30
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
31
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
32
|
+
}
|
|
33
|
+
}
|