@prismer/sdk 1.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/README.md +982 -0
- package/dist/cli.js +1005 -0
- package/dist/index.d.mts +744 -0
- package/dist/index.d.ts +744 -0
- package/dist/index.js +864 -0
- package/dist/index.mjs +822 -0
- package/package.json +58 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,822 @@
|
|
|
1
|
+
// src/realtime.ts
|
|
2
|
+
var TypedEmitter = class {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
5
|
+
}
|
|
6
|
+
on(event, cb) {
|
|
7
|
+
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
8
|
+
this.listeners.get(event).add(cb);
|
|
9
|
+
return this;
|
|
10
|
+
}
|
|
11
|
+
off(event, cb) {
|
|
12
|
+
this.listeners.get(event)?.delete(cb);
|
|
13
|
+
return this;
|
|
14
|
+
}
|
|
15
|
+
once(event, cb) {
|
|
16
|
+
const wrapper = (payload) => {
|
|
17
|
+
this.off(event, wrapper);
|
|
18
|
+
cb(payload);
|
|
19
|
+
};
|
|
20
|
+
return this.on(event, wrapper);
|
|
21
|
+
}
|
|
22
|
+
emit(event, payload) {
|
|
23
|
+
const set = this.listeners.get(event);
|
|
24
|
+
if (set) {
|
|
25
|
+
for (const cb of set) {
|
|
26
|
+
try {
|
|
27
|
+
cb(payload);
|
|
28
|
+
} catch (_) {
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
removeAllListeners() {
|
|
34
|
+
this.listeners.clear();
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
var Reconnector = class {
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.attempt = 0;
|
|
40
|
+
this.connectedAt = 0;
|
|
41
|
+
this.baseDelay = config.reconnectBaseDelay ?? 1e3;
|
|
42
|
+
this.maxDelay = config.reconnectMaxDelay ?? 3e4;
|
|
43
|
+
this.maxAttempts = config.maxReconnectAttempts ?? 10;
|
|
44
|
+
}
|
|
45
|
+
get shouldReconnect() {
|
|
46
|
+
return this.maxAttempts === 0 || this.attempt < this.maxAttempts;
|
|
47
|
+
}
|
|
48
|
+
get currentAttempt() {
|
|
49
|
+
return this.attempt;
|
|
50
|
+
}
|
|
51
|
+
markConnected() {
|
|
52
|
+
this.connectedAt = Date.now();
|
|
53
|
+
}
|
|
54
|
+
nextDelay() {
|
|
55
|
+
if (this.connectedAt > 0 && Date.now() - this.connectedAt > 6e4) {
|
|
56
|
+
this.attempt = 0;
|
|
57
|
+
}
|
|
58
|
+
const jitter = Math.random() * this.baseDelay * 0.5;
|
|
59
|
+
const delay = Math.min(this.baseDelay * Math.pow(2, this.attempt) + jitter, this.maxDelay);
|
|
60
|
+
this.attempt++;
|
|
61
|
+
return delay;
|
|
62
|
+
}
|
|
63
|
+
reset() {
|
|
64
|
+
this.attempt = 0;
|
|
65
|
+
this.connectedAt = 0;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var RealtimeWSClient = class extends TypedEmitter {
|
|
69
|
+
constructor(baseUrl, config) {
|
|
70
|
+
super();
|
|
71
|
+
this.ws = null;
|
|
72
|
+
this.heartbeatTimer = null;
|
|
73
|
+
this.pongTimer = null;
|
|
74
|
+
this.reconnectTimer = null;
|
|
75
|
+
this.pendingPings = /* @__PURE__ */ new Map();
|
|
76
|
+
this._state = "disconnected";
|
|
77
|
+
this.intentionalClose = false;
|
|
78
|
+
this.pingCounter = 0;
|
|
79
|
+
this.handleMessage = (ev) => {
|
|
80
|
+
try {
|
|
81
|
+
const msg = JSON.parse(typeof ev.data === "string" ? ev.data : ev.data.toString());
|
|
82
|
+
const { type, payload } = msg;
|
|
83
|
+
if (type === "pong" && payload?.requestId) {
|
|
84
|
+
const pending = this.pendingPings.get(payload.requestId);
|
|
85
|
+
if (pending) {
|
|
86
|
+
clearTimeout(pending.timer);
|
|
87
|
+
pending.resolve(payload);
|
|
88
|
+
this.pendingPings.delete(payload.requestId);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this.emit(type, payload);
|
|
92
|
+
} catch (_) {
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
this.handleClose = (ev) => {
|
|
96
|
+
this.stopHeartbeat();
|
|
97
|
+
this.clearPendingPings();
|
|
98
|
+
this.ws = null;
|
|
99
|
+
if (this.intentionalClose) return;
|
|
100
|
+
this._state = "disconnected";
|
|
101
|
+
this.emit("disconnected", { code: ev.code, reason: ev.reason });
|
|
102
|
+
if (this.config.autoReconnect && this.reconnector.shouldReconnect) {
|
|
103
|
+
this.scheduleReconnect();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const base = baseUrl.replace(/^http/, "ws");
|
|
107
|
+
this.wsUrl = `${base}/ws?token=${config.token}`;
|
|
108
|
+
this.config = {
|
|
109
|
+
autoReconnect: true,
|
|
110
|
+
heartbeatInterval: 25e3,
|
|
111
|
+
...config
|
|
112
|
+
};
|
|
113
|
+
this.reconnector = new Reconnector(config);
|
|
114
|
+
this.WS = config.WebSocket || WebSocket;
|
|
115
|
+
}
|
|
116
|
+
get state() {
|
|
117
|
+
return this._state;
|
|
118
|
+
}
|
|
119
|
+
async connect() {
|
|
120
|
+
if (this._state === "connected" || this._state === "connecting") return;
|
|
121
|
+
this._state = "connecting";
|
|
122
|
+
this.intentionalClose = false;
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
try {
|
|
125
|
+
this.ws = new this.WS(this.wsUrl);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
this._state = "disconnected";
|
|
128
|
+
reject(err);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const onOpen = () => {
|
|
132
|
+
cleanup();
|
|
133
|
+
};
|
|
134
|
+
const onFirstMessage = (ev) => {
|
|
135
|
+
try {
|
|
136
|
+
const msg = JSON.parse(typeof ev.data === "string" ? ev.data : ev.data.toString());
|
|
137
|
+
if (msg.type === "authenticated") {
|
|
138
|
+
this._state = "connected";
|
|
139
|
+
this.reconnector.markConnected();
|
|
140
|
+
this.startHeartbeat();
|
|
141
|
+
this.emit("authenticated", msg.payload);
|
|
142
|
+
this.emit("connected", void 0);
|
|
143
|
+
this.ws.removeEventListener("message", onFirstMessage);
|
|
144
|
+
this.ws.addEventListener("message", this.handleMessage);
|
|
145
|
+
resolve();
|
|
146
|
+
}
|
|
147
|
+
} catch (_) {
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
const onError = (ev) => {
|
|
151
|
+
cleanup();
|
|
152
|
+
if (this._state === "connecting") {
|
|
153
|
+
this._state = "disconnected";
|
|
154
|
+
reject(new Error("WebSocket connection failed"));
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
const onClose = (ev) => {
|
|
158
|
+
cleanup();
|
|
159
|
+
if (this._state === "connecting") {
|
|
160
|
+
this._state = "disconnected";
|
|
161
|
+
reject(new Error(`WebSocket closed during connect: ${ev.code} ${ev.reason}`));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
const cleanup = () => {
|
|
165
|
+
this.ws?.removeEventListener("error", onError);
|
|
166
|
+
this.ws?.removeEventListener("close", onClose);
|
|
167
|
+
};
|
|
168
|
+
this.ws.addEventListener("open", onOpen);
|
|
169
|
+
this.ws.addEventListener("message", onFirstMessage);
|
|
170
|
+
this.ws.addEventListener("error", onError);
|
|
171
|
+
this.ws.addEventListener("close", onClose);
|
|
172
|
+
this.ws.addEventListener("close", this.handleClose);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
disconnect(code = 1e3, reason = "client disconnect") {
|
|
176
|
+
this.intentionalClose = true;
|
|
177
|
+
this.stopHeartbeat();
|
|
178
|
+
this.clearReconnectTimer();
|
|
179
|
+
this.clearPendingPings();
|
|
180
|
+
if (this.ws) {
|
|
181
|
+
this.ws.removeEventListener("message", this.handleMessage);
|
|
182
|
+
this.ws.removeEventListener("close", this.handleClose);
|
|
183
|
+
if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {
|
|
184
|
+
this.ws.close(code, reason);
|
|
185
|
+
}
|
|
186
|
+
this.ws = null;
|
|
187
|
+
}
|
|
188
|
+
this._state = "disconnected";
|
|
189
|
+
this.emit("disconnected", { code, reason });
|
|
190
|
+
}
|
|
191
|
+
// --- Commands ---
|
|
192
|
+
joinConversation(conversationId) {
|
|
193
|
+
this.sendRaw({ type: "conversation.join", payload: { conversationId } });
|
|
194
|
+
}
|
|
195
|
+
sendMessage(conversationId, content, type = "text") {
|
|
196
|
+
this.sendRaw({
|
|
197
|
+
type: "message.send",
|
|
198
|
+
payload: { conversationId, content, type },
|
|
199
|
+
requestId: `msg-${++this.pingCounter}`
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
startTyping(conversationId) {
|
|
203
|
+
this.sendRaw({ type: "typing.start", payload: { conversationId } });
|
|
204
|
+
}
|
|
205
|
+
stopTyping(conversationId) {
|
|
206
|
+
this.sendRaw({ type: "typing.stop", payload: { conversationId } });
|
|
207
|
+
}
|
|
208
|
+
updatePresence(status) {
|
|
209
|
+
this.sendRaw({ type: "presence.update", payload: { status } });
|
|
210
|
+
}
|
|
211
|
+
send(command) {
|
|
212
|
+
this.sendRaw(command);
|
|
213
|
+
}
|
|
214
|
+
ping() {
|
|
215
|
+
const requestId = `ping-${++this.pingCounter}`;
|
|
216
|
+
return new Promise((resolve, reject) => {
|
|
217
|
+
const timer = setTimeout(() => {
|
|
218
|
+
this.pendingPings.delete(requestId);
|
|
219
|
+
reject(new Error("Ping timeout"));
|
|
220
|
+
}, 1e4);
|
|
221
|
+
this.pendingPings.set(requestId, { resolve, timer });
|
|
222
|
+
this.sendRaw({ type: "ping", payload: { requestId } });
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// --- Internal ---
|
|
226
|
+
sendRaw(data) {
|
|
227
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
228
|
+
this.ws.send(JSON.stringify(data));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
scheduleReconnect() {
|
|
232
|
+
const delay = this.reconnector.nextDelay();
|
|
233
|
+
this._state = "reconnecting";
|
|
234
|
+
this.emit("reconnecting", { attempt: this.reconnector.currentAttempt, delayMs: delay });
|
|
235
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
236
|
+
try {
|
|
237
|
+
await this.connect();
|
|
238
|
+
} catch (_) {
|
|
239
|
+
if (this.config.autoReconnect && this.reconnector.shouldReconnect) {
|
|
240
|
+
this.scheduleReconnect();
|
|
241
|
+
} else {
|
|
242
|
+
this._state = "disconnected";
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}, delay);
|
|
246
|
+
}
|
|
247
|
+
startHeartbeat() {
|
|
248
|
+
this.stopHeartbeat();
|
|
249
|
+
this.heartbeatTimer = setInterval(() => {
|
|
250
|
+
if (this._state !== "connected") return;
|
|
251
|
+
const requestId = `hb-${++this.pingCounter}`;
|
|
252
|
+
this.sendRaw({ type: "ping", payload: { requestId } });
|
|
253
|
+
this.pongTimer = setTimeout(() => {
|
|
254
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
255
|
+
this.ws.close(4e3, "heartbeat timeout");
|
|
256
|
+
}
|
|
257
|
+
}, 1e4);
|
|
258
|
+
const onPong = (payload) => {
|
|
259
|
+
if (this.pongTimer) {
|
|
260
|
+
clearTimeout(this.pongTimer);
|
|
261
|
+
this.pongTimer = null;
|
|
262
|
+
}
|
|
263
|
+
this.off("pong", onPong);
|
|
264
|
+
};
|
|
265
|
+
this.on("pong", onPong);
|
|
266
|
+
}, this.config.heartbeatInterval);
|
|
267
|
+
}
|
|
268
|
+
stopHeartbeat() {
|
|
269
|
+
if (this.heartbeatTimer) {
|
|
270
|
+
clearInterval(this.heartbeatTimer);
|
|
271
|
+
this.heartbeatTimer = null;
|
|
272
|
+
}
|
|
273
|
+
if (this.pongTimer) {
|
|
274
|
+
clearTimeout(this.pongTimer);
|
|
275
|
+
this.pongTimer = null;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
clearReconnectTimer() {
|
|
279
|
+
if (this.reconnectTimer) {
|
|
280
|
+
clearTimeout(this.reconnectTimer);
|
|
281
|
+
this.reconnectTimer = null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
clearPendingPings() {
|
|
285
|
+
for (const [, { timer }] of this.pendingPings) {
|
|
286
|
+
clearTimeout(timer);
|
|
287
|
+
}
|
|
288
|
+
this.pendingPings.clear();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
var RealtimeSSEClient = class extends TypedEmitter {
|
|
292
|
+
constructor(baseUrl, config) {
|
|
293
|
+
super();
|
|
294
|
+
this.abortController = null;
|
|
295
|
+
this.reconnectTimer = null;
|
|
296
|
+
this.heartbeatWatchdog = null;
|
|
297
|
+
this.lastDataTime = 0;
|
|
298
|
+
this._state = "disconnected";
|
|
299
|
+
this.intentionalClose = false;
|
|
300
|
+
this.sseUrl = `${baseUrl}/sse?token=${config.token}`;
|
|
301
|
+
this.config = {
|
|
302
|
+
autoReconnect: true,
|
|
303
|
+
...config
|
|
304
|
+
};
|
|
305
|
+
this.reconnector = new Reconnector(config);
|
|
306
|
+
this.fetchFn = config.fetch || fetch;
|
|
307
|
+
}
|
|
308
|
+
get state() {
|
|
309
|
+
return this._state;
|
|
310
|
+
}
|
|
311
|
+
async connect() {
|
|
312
|
+
if (this._state === "connected" || this._state === "connecting") return;
|
|
313
|
+
this._state = "connecting";
|
|
314
|
+
this.intentionalClose = false;
|
|
315
|
+
this.abortController = new AbortController();
|
|
316
|
+
const response = await this.fetchFn(this.sseUrl, {
|
|
317
|
+
headers: { "Accept": "text/event-stream" },
|
|
318
|
+
signal: this.abortController.signal
|
|
319
|
+
});
|
|
320
|
+
if (!response.ok) {
|
|
321
|
+
this._state = "disconnected";
|
|
322
|
+
throw new Error(`SSE connection failed: ${response.status}`);
|
|
323
|
+
}
|
|
324
|
+
if (!response.body) {
|
|
325
|
+
this._state = "disconnected";
|
|
326
|
+
throw new Error("SSE response has no body");
|
|
327
|
+
}
|
|
328
|
+
this._state = "connected";
|
|
329
|
+
this.reconnector.markConnected();
|
|
330
|
+
this.lastDataTime = Date.now();
|
|
331
|
+
this.startHeartbeatWatchdog();
|
|
332
|
+
this.emit("connected", void 0);
|
|
333
|
+
this.readStream(response.body);
|
|
334
|
+
}
|
|
335
|
+
disconnect() {
|
|
336
|
+
this.intentionalClose = true;
|
|
337
|
+
this.stopHeartbeatWatchdog();
|
|
338
|
+
this.clearReconnectTimer();
|
|
339
|
+
if (this.abortController) {
|
|
340
|
+
this.abortController.abort();
|
|
341
|
+
this.abortController = null;
|
|
342
|
+
}
|
|
343
|
+
this._state = "disconnected";
|
|
344
|
+
this.emit("disconnected", { code: 1e3, reason: "client disconnect" });
|
|
345
|
+
}
|
|
346
|
+
// --- Internal ---
|
|
347
|
+
async readStream(body) {
|
|
348
|
+
const reader = body.getReader();
|
|
349
|
+
const decoder = new TextDecoder();
|
|
350
|
+
let buffer = "";
|
|
351
|
+
try {
|
|
352
|
+
while (true) {
|
|
353
|
+
const { done, value } = await reader.read();
|
|
354
|
+
if (done) break;
|
|
355
|
+
buffer += decoder.decode(value, { stream: true });
|
|
356
|
+
const lines = buffer.split("\n");
|
|
357
|
+
buffer = lines.pop() || "";
|
|
358
|
+
for (const line of lines) {
|
|
359
|
+
this.lastDataTime = Date.now();
|
|
360
|
+
if (line.startsWith(":")) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
if (line.startsWith("data: ")) {
|
|
364
|
+
const jsonStr = line.slice(6);
|
|
365
|
+
try {
|
|
366
|
+
const msg = JSON.parse(jsonStr);
|
|
367
|
+
this.emit(msg.type, msg.payload);
|
|
368
|
+
} catch (_) {
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
} catch (err) {
|
|
374
|
+
if (this.intentionalClose) return;
|
|
375
|
+
} finally {
|
|
376
|
+
reader.releaseLock();
|
|
377
|
+
}
|
|
378
|
+
if (this.intentionalClose) return;
|
|
379
|
+
this._state = "disconnected";
|
|
380
|
+
this.stopHeartbeatWatchdog();
|
|
381
|
+
this.emit("disconnected", { code: 0, reason: "stream ended" });
|
|
382
|
+
if (this.config.autoReconnect && this.reconnector.shouldReconnect) {
|
|
383
|
+
this.scheduleReconnect();
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
scheduleReconnect() {
|
|
387
|
+
const delay = this.reconnector.nextDelay();
|
|
388
|
+
this._state = "reconnecting";
|
|
389
|
+
this.emit("reconnecting", { attempt: this.reconnector.currentAttempt, delayMs: delay });
|
|
390
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
391
|
+
try {
|
|
392
|
+
await this.connect();
|
|
393
|
+
} catch (_) {
|
|
394
|
+
if (this.config.autoReconnect && this.reconnector.shouldReconnect) {
|
|
395
|
+
this.scheduleReconnect();
|
|
396
|
+
} else {
|
|
397
|
+
this._state = "disconnected";
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}, delay);
|
|
401
|
+
}
|
|
402
|
+
startHeartbeatWatchdog() {
|
|
403
|
+
this.stopHeartbeatWatchdog();
|
|
404
|
+
this.heartbeatWatchdog = setInterval(() => {
|
|
405
|
+
if (Date.now() - this.lastDataTime > 45e3) {
|
|
406
|
+
this.stopHeartbeatWatchdog();
|
|
407
|
+
if (this.abortController) {
|
|
408
|
+
this.abortController.abort();
|
|
409
|
+
this.abortController = null;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}, 15e3);
|
|
413
|
+
}
|
|
414
|
+
stopHeartbeatWatchdog() {
|
|
415
|
+
if (this.heartbeatWatchdog) {
|
|
416
|
+
clearInterval(this.heartbeatWatchdog);
|
|
417
|
+
this.heartbeatWatchdog = null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
clearReconnectTimer() {
|
|
421
|
+
if (this.reconnectTimer) {
|
|
422
|
+
clearTimeout(this.reconnectTimer);
|
|
423
|
+
this.reconnectTimer = null;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
// src/types.ts
|
|
429
|
+
var ENVIRONMENTS = {
|
|
430
|
+
production: "https://prismer.cloud",
|
|
431
|
+
testing: "https://cloud.prismer.dev"
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
// src/index.ts
|
|
435
|
+
var AccountClient = class {
|
|
436
|
+
constructor(_r) {
|
|
437
|
+
this._r = _r;
|
|
438
|
+
}
|
|
439
|
+
/** Register an agent or human identity */
|
|
440
|
+
async register(options) {
|
|
441
|
+
return this._r("POST", "/api/im/register", options);
|
|
442
|
+
}
|
|
443
|
+
/** Get own identity, stats, bindings, credits */
|
|
444
|
+
async me() {
|
|
445
|
+
return this._r("GET", "/api/im/me");
|
|
446
|
+
}
|
|
447
|
+
/** Refresh JWT token */
|
|
448
|
+
async refreshToken() {
|
|
449
|
+
return this._r("POST", "/api/im/token/refresh");
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
var DirectClient = class {
|
|
453
|
+
constructor(_r) {
|
|
454
|
+
this._r = _r;
|
|
455
|
+
}
|
|
456
|
+
/** Send a direct message to a user */
|
|
457
|
+
async send(userId, content, options) {
|
|
458
|
+
return this._r("POST", `/api/im/direct/${userId}/messages`, {
|
|
459
|
+
content,
|
|
460
|
+
type: options?.type ?? "text",
|
|
461
|
+
metadata: options?.metadata
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
/** Get direct message history with a user */
|
|
465
|
+
async getMessages(userId, options) {
|
|
466
|
+
const query = {};
|
|
467
|
+
if (options?.limit) query.limit = String(options.limit);
|
|
468
|
+
if (options?.offset) query.offset = String(options.offset);
|
|
469
|
+
return this._r("GET", `/api/im/direct/${userId}/messages`, void 0, query);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
var GroupsClient = class {
|
|
473
|
+
constructor(_r) {
|
|
474
|
+
this._r = _r;
|
|
475
|
+
}
|
|
476
|
+
/** Create a group chat */
|
|
477
|
+
async create(options) {
|
|
478
|
+
return this._r("POST", "/api/im/groups", options);
|
|
479
|
+
}
|
|
480
|
+
/** List groups you belong to */
|
|
481
|
+
async list() {
|
|
482
|
+
return this._r("GET", "/api/im/groups");
|
|
483
|
+
}
|
|
484
|
+
/** Get group details */
|
|
485
|
+
async get(groupId) {
|
|
486
|
+
return this._r("GET", `/api/im/groups/${groupId}`);
|
|
487
|
+
}
|
|
488
|
+
/** Send a message to a group */
|
|
489
|
+
async send(groupId, content, options) {
|
|
490
|
+
return this._r("POST", `/api/im/groups/${groupId}/messages`, {
|
|
491
|
+
content,
|
|
492
|
+
type: options?.type ?? "text",
|
|
493
|
+
metadata: options?.metadata
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
/** Get group message history */
|
|
497
|
+
async getMessages(groupId, options) {
|
|
498
|
+
const query = {};
|
|
499
|
+
if (options?.limit) query.limit = String(options.limit);
|
|
500
|
+
if (options?.offset) query.offset = String(options.offset);
|
|
501
|
+
return this._r("GET", `/api/im/groups/${groupId}/messages`, void 0, query);
|
|
502
|
+
}
|
|
503
|
+
/** Add a member to a group (owner/admin only) */
|
|
504
|
+
async addMember(groupId, userId) {
|
|
505
|
+
return this._r("POST", `/api/im/groups/${groupId}/members`, { userId });
|
|
506
|
+
}
|
|
507
|
+
/** Remove a member from a group (owner/admin only) */
|
|
508
|
+
async removeMember(groupId, userId) {
|
|
509
|
+
return this._r("DELETE", `/api/im/groups/${groupId}/members/${userId}`);
|
|
510
|
+
}
|
|
511
|
+
};
|
|
512
|
+
var ConversationsClient = class {
|
|
513
|
+
constructor(_r) {
|
|
514
|
+
this._r = _r;
|
|
515
|
+
}
|
|
516
|
+
/** List conversations */
|
|
517
|
+
async list(options) {
|
|
518
|
+
const query = {};
|
|
519
|
+
if (options?.withUnread) query.withUnread = "true";
|
|
520
|
+
if (options?.unreadOnly) query.unreadOnly = "true";
|
|
521
|
+
return this._r("GET", "/api/im/conversations", void 0, query);
|
|
522
|
+
}
|
|
523
|
+
/** Get conversation details */
|
|
524
|
+
async get(conversationId) {
|
|
525
|
+
return this._r("GET", `/api/im/conversations/${conversationId}`);
|
|
526
|
+
}
|
|
527
|
+
/** Create a direct conversation */
|
|
528
|
+
async createDirect(userId) {
|
|
529
|
+
return this._r("POST", "/api/im/conversations/direct", { userId });
|
|
530
|
+
}
|
|
531
|
+
/** Mark a conversation as read */
|
|
532
|
+
async markAsRead(conversationId) {
|
|
533
|
+
return this._r("POST", `/api/im/conversations/${conversationId}/read`);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
var MessagesClient = class {
|
|
537
|
+
constructor(_r) {
|
|
538
|
+
this._r = _r;
|
|
539
|
+
}
|
|
540
|
+
/** Send a message to a conversation */
|
|
541
|
+
async send(conversationId, content, options) {
|
|
542
|
+
return this._r("POST", `/api/im/messages/${conversationId}`, {
|
|
543
|
+
content,
|
|
544
|
+
type: options?.type ?? "text",
|
|
545
|
+
metadata: options?.metadata
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
/** Get message history for a conversation */
|
|
549
|
+
async getHistory(conversationId, options) {
|
|
550
|
+
const query = {};
|
|
551
|
+
if (options?.limit) query.limit = String(options.limit);
|
|
552
|
+
if (options?.offset) query.offset = String(options.offset);
|
|
553
|
+
return this._r("GET", `/api/im/messages/${conversationId}`, void 0, query);
|
|
554
|
+
}
|
|
555
|
+
/** Edit a message */
|
|
556
|
+
async edit(conversationId, messageId, content) {
|
|
557
|
+
return this._r("PATCH", `/api/im/messages/${conversationId}/${messageId}`, { content });
|
|
558
|
+
}
|
|
559
|
+
/** Delete a message */
|
|
560
|
+
async delete(conversationId, messageId) {
|
|
561
|
+
return this._r("DELETE", `/api/im/messages/${conversationId}/${messageId}`);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
var ContactsClient = class {
|
|
565
|
+
constructor(_r) {
|
|
566
|
+
this._r = _r;
|
|
567
|
+
}
|
|
568
|
+
/** List contacts (users you've communicated with) */
|
|
569
|
+
async list() {
|
|
570
|
+
return this._r("GET", "/api/im/contacts");
|
|
571
|
+
}
|
|
572
|
+
/** Discover agents by capability or type */
|
|
573
|
+
async discover(options) {
|
|
574
|
+
const query = {};
|
|
575
|
+
if (options?.type) query.type = options.type;
|
|
576
|
+
if (options?.capability) query.capability = options.capability;
|
|
577
|
+
return this._r("GET", "/api/im/discover", void 0, query);
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
var BindingsClient = class {
|
|
581
|
+
constructor(_r) {
|
|
582
|
+
this._r = _r;
|
|
583
|
+
}
|
|
584
|
+
/** Create a social binding */
|
|
585
|
+
async create(options) {
|
|
586
|
+
return this._r("POST", "/api/im/bindings", options);
|
|
587
|
+
}
|
|
588
|
+
/** Verify a binding with 6-digit code */
|
|
589
|
+
async verify(bindingId, code) {
|
|
590
|
+
return this._r("POST", `/api/im/bindings/${bindingId}/verify`, { code });
|
|
591
|
+
}
|
|
592
|
+
/** List bindings */
|
|
593
|
+
async list() {
|
|
594
|
+
return this._r("GET", "/api/im/bindings");
|
|
595
|
+
}
|
|
596
|
+
/** Delete a binding */
|
|
597
|
+
async delete(bindingId) {
|
|
598
|
+
return this._r("DELETE", `/api/im/bindings/${bindingId}`);
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
var CreditsClient = class {
|
|
602
|
+
constructor(_r) {
|
|
603
|
+
this._r = _r;
|
|
604
|
+
}
|
|
605
|
+
/** Get credits balance */
|
|
606
|
+
async get() {
|
|
607
|
+
return this._r("GET", "/api/im/credits");
|
|
608
|
+
}
|
|
609
|
+
/** Get credit transaction history */
|
|
610
|
+
async transactions(options) {
|
|
611
|
+
const query = {};
|
|
612
|
+
if (options?.limit) query.limit = String(options.limit);
|
|
613
|
+
if (options?.offset) query.offset = String(options.offset);
|
|
614
|
+
return this._r("GET", "/api/im/credits/transactions", void 0, query);
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
var WorkspaceClient = class {
|
|
618
|
+
constructor(_r) {
|
|
619
|
+
this._r = _r;
|
|
620
|
+
}
|
|
621
|
+
/** Initialize a 1:1 workspace (1 user + 1 agent) */
|
|
622
|
+
async init() {
|
|
623
|
+
return this._r("POST", "/api/im/workspace/init");
|
|
624
|
+
}
|
|
625
|
+
/** Initialize a group workspace (multi-user + multi-agent) */
|
|
626
|
+
async initGroup() {
|
|
627
|
+
return this._r("POST", "/api/im/workspace/init-group");
|
|
628
|
+
}
|
|
629
|
+
/** Add an agent to a workspace */
|
|
630
|
+
async addAgent(workspaceId, agentId) {
|
|
631
|
+
return this._r("POST", `/api/im/workspace/${workspaceId}/agents`, { agentId });
|
|
632
|
+
}
|
|
633
|
+
/** List agents in a workspace */
|
|
634
|
+
async listAgents(workspaceId) {
|
|
635
|
+
return this._r("GET", `/api/im/workspace/${workspaceId}/agents`);
|
|
636
|
+
}
|
|
637
|
+
/** @mention autocomplete */
|
|
638
|
+
async mentionAutocomplete(query) {
|
|
639
|
+
const q = {};
|
|
640
|
+
if (query) q.q = query;
|
|
641
|
+
return this._r("GET", "/api/im/workspace/mentions/autocomplete", void 0, q);
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
var IMRealtimeClient = class {
|
|
645
|
+
constructor(_wsBase) {
|
|
646
|
+
this._wsBase = _wsBase;
|
|
647
|
+
}
|
|
648
|
+
/** Get the WebSocket URL */
|
|
649
|
+
wsUrl(token) {
|
|
650
|
+
const base = this._wsBase.replace(/^http/, "ws");
|
|
651
|
+
return token ? `${base}/ws?token=${token}` : `${base}/ws`;
|
|
652
|
+
}
|
|
653
|
+
/** Get the SSE URL */
|
|
654
|
+
sseUrl(token) {
|
|
655
|
+
return token ? `${this._wsBase}/sse?token=${token}` : `${this._wsBase}/sse`;
|
|
656
|
+
}
|
|
657
|
+
/** Create a WebSocket client. Call .connect() to establish connection. */
|
|
658
|
+
connectWS(config) {
|
|
659
|
+
return new RealtimeWSClient(this._wsBase, config);
|
|
660
|
+
}
|
|
661
|
+
/** Create an SSE client. Call .connect() to establish connection. */
|
|
662
|
+
connectSSE(config) {
|
|
663
|
+
return new RealtimeSSEClient(this._wsBase, config);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var IMClient = class {
|
|
667
|
+
constructor(request, wsBase) {
|
|
668
|
+
this.account = new AccountClient(request);
|
|
669
|
+
this.direct = new DirectClient(request);
|
|
670
|
+
this.groups = new GroupsClient(request);
|
|
671
|
+
this.conversations = new ConversationsClient(request);
|
|
672
|
+
this.messages = new MessagesClient(request);
|
|
673
|
+
this.contacts = new ContactsClient(request);
|
|
674
|
+
this.bindings = new BindingsClient(request);
|
|
675
|
+
this.credits = new CreditsClient(request);
|
|
676
|
+
this.workspace = new WorkspaceClient(request);
|
|
677
|
+
this.realtime = new IMRealtimeClient(wsBase);
|
|
678
|
+
}
|
|
679
|
+
/** IM health check */
|
|
680
|
+
async health() {
|
|
681
|
+
return this.account["_r"]("GET", "/api/im/health");
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
var PrismerClient = class {
|
|
685
|
+
constructor(config) {
|
|
686
|
+
if (!config.apiKey) {
|
|
687
|
+
throw new Error("apiKey is required");
|
|
688
|
+
}
|
|
689
|
+
if (!config.apiKey.startsWith("sk-prismer-") && !config.apiKey.startsWith("eyJ")) {
|
|
690
|
+
console.warn('Warning: API key should start with "sk-prismer-" (or "eyJ" for IM JWT)');
|
|
691
|
+
}
|
|
692
|
+
this.apiKey = config.apiKey;
|
|
693
|
+
const envUrl = ENVIRONMENTS[config.environment || "production"];
|
|
694
|
+
this.baseUrl = (config.baseUrl || envUrl).replace(/\/$/, "");
|
|
695
|
+
this.timeout = config.timeout || 3e4;
|
|
696
|
+
this.fetchFn = config.fetch || fetch;
|
|
697
|
+
this.imAgent = config.imAgent;
|
|
698
|
+
this.im = new IMClient(
|
|
699
|
+
(method, path, body, query) => this._request(method, path, body, query),
|
|
700
|
+
this.baseUrl
|
|
701
|
+
);
|
|
702
|
+
}
|
|
703
|
+
// --------------------------------------------------------------------------
|
|
704
|
+
// Internal request helper
|
|
705
|
+
// --------------------------------------------------------------------------
|
|
706
|
+
async _request(method, path, body, query) {
|
|
707
|
+
const controller = new AbortController();
|
|
708
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
709
|
+
try {
|
|
710
|
+
let url = `${this.baseUrl}${path}`;
|
|
711
|
+
if (query && Object.keys(query).length > 0) {
|
|
712
|
+
url += "?" + new URLSearchParams(query).toString();
|
|
713
|
+
}
|
|
714
|
+
const headers = {
|
|
715
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
716
|
+
};
|
|
717
|
+
if (this.imAgent) {
|
|
718
|
+
headers["X-IM-Agent"] = this.imAgent;
|
|
719
|
+
}
|
|
720
|
+
const init = { method, headers, signal: controller.signal };
|
|
721
|
+
if (body !== void 0) {
|
|
722
|
+
headers["Content-Type"] = "application/json";
|
|
723
|
+
init.body = JSON.stringify(body);
|
|
724
|
+
}
|
|
725
|
+
const response = await this.fetchFn(url, init);
|
|
726
|
+
const data = await response.json();
|
|
727
|
+
if (!response.ok) {
|
|
728
|
+
const err = data.error || { code: "HTTP_ERROR", message: `Request failed with status ${response.status}` };
|
|
729
|
+
return { ...data, success: false, ok: false, error: err };
|
|
730
|
+
}
|
|
731
|
+
return data;
|
|
732
|
+
} catch (error) {
|
|
733
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
734
|
+
return { success: false, ok: false, error: { code: "TIMEOUT", message: "Request timed out" } };
|
|
735
|
+
}
|
|
736
|
+
return {
|
|
737
|
+
success: false,
|
|
738
|
+
ok: false,
|
|
739
|
+
error: { code: "NETWORK_ERROR", message: error instanceof Error ? error.message : "Unknown error" }
|
|
740
|
+
};
|
|
741
|
+
} finally {
|
|
742
|
+
clearTimeout(timeoutId);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
// --------------------------------------------------------------------------
|
|
746
|
+
// Context API
|
|
747
|
+
// --------------------------------------------------------------------------
|
|
748
|
+
/** Load content from URL(s) or search query */
|
|
749
|
+
async load(input, options = {}) {
|
|
750
|
+
return this._request("POST", "/api/context/load", {
|
|
751
|
+
input,
|
|
752
|
+
inputType: options.inputType,
|
|
753
|
+
processUncached: options.processUncached,
|
|
754
|
+
search: options.search,
|
|
755
|
+
processing: options.processing,
|
|
756
|
+
return: options.return,
|
|
757
|
+
ranking: options.ranking
|
|
758
|
+
});
|
|
759
|
+
}
|
|
760
|
+
/** Save content to Prismer cache */
|
|
761
|
+
async save(options) {
|
|
762
|
+
return this._request("POST", "/api/context/save", options);
|
|
763
|
+
}
|
|
764
|
+
/** Batch save multiple items (max 50) */
|
|
765
|
+
async saveBatch(items) {
|
|
766
|
+
return this.save({ items });
|
|
767
|
+
}
|
|
768
|
+
// --------------------------------------------------------------------------
|
|
769
|
+
// Parse API
|
|
770
|
+
// --------------------------------------------------------------------------
|
|
771
|
+
/** Parse a document (PDF, image) into structured content */
|
|
772
|
+
async parse(options) {
|
|
773
|
+
return this._request("POST", "/api/parse", options);
|
|
774
|
+
}
|
|
775
|
+
/** Convenience: parse a PDF by URL */
|
|
776
|
+
async parsePdf(url, mode = "fast") {
|
|
777
|
+
return this.parse({ url, mode });
|
|
778
|
+
}
|
|
779
|
+
/** Check status of an async parse task */
|
|
780
|
+
async parseStatus(taskId) {
|
|
781
|
+
return this._request("GET", `/api/parse/status/${taskId}`);
|
|
782
|
+
}
|
|
783
|
+
/** Get result of a completed async parse task */
|
|
784
|
+
async parseResult(taskId) {
|
|
785
|
+
return this._request("GET", `/api/parse/result/${taskId}`);
|
|
786
|
+
}
|
|
787
|
+
// --------------------------------------------------------------------------
|
|
788
|
+
// Convenience
|
|
789
|
+
// --------------------------------------------------------------------------
|
|
790
|
+
/** Search for content (convenience wrapper around load with query mode) */
|
|
791
|
+
async search(query, options) {
|
|
792
|
+
return this.load(query, {
|
|
793
|
+
inputType: "query",
|
|
794
|
+
search: options?.topK ? { topK: options.topK } : void 0,
|
|
795
|
+
return: options?.returnTopK || options?.format ? { topK: options?.returnTopK, format: options?.format } : void 0,
|
|
796
|
+
ranking: options?.ranking ? { preset: options.ranking } : void 0
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
var index_default = PrismerClient;
|
|
801
|
+
function createClient(config) {
|
|
802
|
+
return new PrismerClient(config);
|
|
803
|
+
}
|
|
804
|
+
export {
|
|
805
|
+
AccountClient,
|
|
806
|
+
BindingsClient,
|
|
807
|
+
ContactsClient,
|
|
808
|
+
ConversationsClient,
|
|
809
|
+
CreditsClient,
|
|
810
|
+
DirectClient,
|
|
811
|
+
ENVIRONMENTS,
|
|
812
|
+
GroupsClient,
|
|
813
|
+
IMClient,
|
|
814
|
+
IMRealtimeClient,
|
|
815
|
+
MessagesClient,
|
|
816
|
+
PrismerClient,
|
|
817
|
+
RealtimeSSEClient,
|
|
818
|
+
RealtimeWSClient,
|
|
819
|
+
WorkspaceClient,
|
|
820
|
+
createClient,
|
|
821
|
+
index_default as default
|
|
822
|
+
};
|