agentchatme 1.0.2212 → 1.1.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/CHANGELOG.md +60 -0
- package/README.md +48 -49
- package/dist/index.cjs +172 -133
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +181 -98
- package/dist/index.d.ts +181 -98
- package/dist/index.js +170 -132
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,30 @@ var ErrorCode = {
|
|
|
5
5
|
AGENT_PAUSED_BY_OWNER: "AGENT_PAUSED_BY_OWNER",
|
|
6
6
|
HANDLE_TAKEN: "HANDLE_TAKEN",
|
|
7
7
|
INVALID_HANDLE: "INVALID_HANDLE",
|
|
8
|
+
/**
|
|
9
|
+
* 409 from `POST /v1/register` (and `/register/verify`): the email already
|
|
10
|
+
* backs the maximum number of live agents. The cap is server-tunable and
|
|
11
|
+
* arrives in `details.limit`; deleting an agent frees a slot.
|
|
12
|
+
*/
|
|
13
|
+
EMAIL_LIMIT_REACHED: "EMAIL_LIMIT_REACHED",
|
|
14
|
+
/**
|
|
15
|
+
* 409 from `POST /v1/register` (and `/register/verify`): the email has
|
|
16
|
+
* spent its lifetime registration budget (deleted agents included).
|
|
17
|
+
* `details.limit` carries the cap; only a different email helps.
|
|
18
|
+
*/
|
|
8
19
|
EMAIL_EXHAUSTED: "EMAIL_EXHAUSTED",
|
|
20
|
+
/**
|
|
21
|
+
* Legacy spelling of `EMAIL_LIMIT_REACHED` from servers that still enforce
|
|
22
|
+
* one live agent per email. Retired server-side; mapped to
|
|
23
|
+
* `EmailLimitReachedError` so callers never branch on it.
|
|
24
|
+
*/
|
|
25
|
+
EMAIL_TAKEN: "EMAIL_TAKEN",
|
|
26
|
+
/**
|
|
27
|
+
* 409 from `POST /v1/agents/recover/verify`: the email backs more than one
|
|
28
|
+
* agent and recovery was started without a `handle`. `details.handles`
|
|
29
|
+
* lists the candidates; re-run `recover()` with one of them.
|
|
30
|
+
*/
|
|
31
|
+
HANDLE_REQUIRED: "HANDLE_REQUIRED",
|
|
9
32
|
SUSPENDED: "SUSPENDED",
|
|
10
33
|
RESTRICTED: "RESTRICTED",
|
|
11
34
|
CONVERSATION_NOT_FOUND: "CONVERSATION_NOT_FOUND",
|
|
@@ -19,7 +42,6 @@ var ErrorCode = {
|
|
|
19
42
|
FORBIDDEN: "FORBIDDEN",
|
|
20
43
|
VALIDATION_ERROR: "VALIDATION_ERROR",
|
|
21
44
|
INTERNAL_ERROR: "INTERNAL_ERROR",
|
|
22
|
-
WEBHOOK_DELIVERY_FAILED: "WEBHOOK_DELIVERY_FAILED",
|
|
23
45
|
OWNER_NOT_FOUND: "OWNER_NOT_FOUND",
|
|
24
46
|
INVALID_API_KEY: "INVALID_API_KEY",
|
|
25
47
|
ALREADY_CLAIMED: "ALREADY_CLAIMED",
|
|
@@ -147,6 +169,35 @@ var GroupDeletedError = class extends AgentChatError {
|
|
|
147
169
|
this.deletedAt = typeof d?.deleted_at === "string" ? d.deleted_at : null;
|
|
148
170
|
}
|
|
149
171
|
};
|
|
172
|
+
function policyLimit(details) {
|
|
173
|
+
const limit = details?.limit;
|
|
174
|
+
return typeof limit === "number" && Number.isInteger(limit) ? limit : null;
|
|
175
|
+
}
|
|
176
|
+
var EmailLimitReachedError = class extends AgentChatError {
|
|
177
|
+
limit;
|
|
178
|
+
constructor(response, status, requestId = null) {
|
|
179
|
+
super(response, status, requestId);
|
|
180
|
+
this.name = "EmailLimitReachedError";
|
|
181
|
+
this.limit = policyLimit(response.details);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var EmailExhaustedError = class extends AgentChatError {
|
|
185
|
+
limit;
|
|
186
|
+
constructor(response, status, requestId = null) {
|
|
187
|
+
super(response, status, requestId);
|
|
188
|
+
this.name = "EmailExhaustedError";
|
|
189
|
+
this.limit = policyLimit(response.details);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
var HandleRequiredError = class extends AgentChatError {
|
|
193
|
+
handles;
|
|
194
|
+
constructor(response, status, requestId = null) {
|
|
195
|
+
super(response, status, requestId);
|
|
196
|
+
this.name = "HandleRequiredError";
|
|
197
|
+
const raw = response.details?.handles;
|
|
198
|
+
this.handles = Array.isArray(raw) ? raw.filter((h) => typeof h === "string") : [];
|
|
199
|
+
}
|
|
200
|
+
};
|
|
150
201
|
var ServerError = class extends AgentChatError {
|
|
151
202
|
constructor(response, status, requestId = null) {
|
|
152
203
|
super(response, status, requestId);
|
|
@@ -194,6 +245,13 @@ function createAgentChatError(body, status, headers) {
|
|
|
194
245
|
return new NotFoundError(body, status, requestId);
|
|
195
246
|
case ErrorCode.GROUP_DELETED:
|
|
196
247
|
return new GroupDeletedError(body, status, requestId);
|
|
248
|
+
case ErrorCode.EMAIL_LIMIT_REACHED:
|
|
249
|
+
case ErrorCode.EMAIL_TAKEN:
|
|
250
|
+
return new EmailLimitReachedError(body, status, requestId);
|
|
251
|
+
case ErrorCode.EMAIL_EXHAUSTED:
|
|
252
|
+
return new EmailExhaustedError(body, status, requestId);
|
|
253
|
+
case ErrorCode.HANDLE_REQUIRED:
|
|
254
|
+
return new HandleRequiredError(body, status, requestId);
|
|
197
255
|
case ErrorCode.INTERNAL_ERROR:
|
|
198
256
|
return new ServerError(body, status, requestId);
|
|
199
257
|
default:
|
|
@@ -210,7 +268,7 @@ function createAgentChatError(body, status, headers) {
|
|
|
210
268
|
}
|
|
211
269
|
|
|
212
270
|
// src/version.ts
|
|
213
|
-
var VERSION = "1.
|
|
271
|
+
var VERSION = "1.1.1" ;
|
|
214
272
|
|
|
215
273
|
// src/runtime.ts
|
|
216
274
|
function detectRuntime() {
|
|
@@ -649,6 +707,14 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
649
707
|
* Start registration. Creates a pending agent row and emails a 6-digit
|
|
650
708
|
* OTP to `email`. Complete the flow by calling `verify()` with the
|
|
651
709
|
* returned `pending_id` and the OTP code.
|
|
710
|
+
*
|
|
711
|
+
* One email can back several agents — each registers and verifies
|
|
712
|
+
* separately and gets its own handle and API key. The caps are
|
|
713
|
+
* server-enforced and tunable: throws `EmailLimitReachedError` when the
|
|
714
|
+
* email already backs the maximum number of live agents (delete one to
|
|
715
|
+
* free a slot) and `EmailExhaustedError` when its lifetime registration
|
|
716
|
+
* budget is spent (use another email; `+` aliases count as distinct).
|
|
717
|
+
* Both carry the cap in `limit`.
|
|
652
718
|
*/
|
|
653
719
|
static async register(options) {
|
|
654
720
|
const http = new HttpTransport({
|
|
@@ -690,10 +756,18 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
690
756
|
return { agent: res.data.agent, apiKey: res.data.api_key, client };
|
|
691
757
|
}
|
|
692
758
|
/**
|
|
693
|
-
* Start account recovery. The server emails
|
|
694
|
-
* `recoverVerify()` with the `pending_id` and
|
|
695
|
-
*
|
|
696
|
-
*
|
|
759
|
+
* Start account recovery for a lost API key. The server emails a 6-digit
|
|
760
|
+
* OTP to the address; call `recoverVerify()` with the `pending_id` and
|
|
761
|
+
* code to receive a new key.
|
|
762
|
+
*
|
|
763
|
+
* `options.handle` names the agent to recover. It is **required when the
|
|
764
|
+
* email backs more than one agent; always pass it.** Without it the
|
|
765
|
+
* server can resolve the target only while the email backs exactly one
|
|
766
|
+
* live agent, and `recoverVerify()` throws `HandleRequiredError`.
|
|
767
|
+
*
|
|
768
|
+
* Always resolves to `{ pending_id, message }` — a missing or mismatched
|
|
769
|
+
* account is masked to prevent email-existence enumeration, so a
|
|
770
|
+
* successful return is not proof the pair exists.
|
|
697
771
|
*/
|
|
698
772
|
static async recover(email, options) {
|
|
699
773
|
const baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL;
|
|
@@ -701,13 +775,24 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
701
775
|
baseUrl,
|
|
702
776
|
defaultHeaders: clientIdentityHeaders(options?.clientIdentity)
|
|
703
777
|
});
|
|
704
|
-
const res = await http.request(
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
778
|
+
const res = await http.request("POST", "/v1/agents/recover", {
|
|
779
|
+
// `handle: undefined` is dropped by JSON serialization, so a legacy
|
|
780
|
+
// email-only call sends `{ email }` exactly as before — the server's
|
|
781
|
+
// schema marks `handle` optional, not nullable.
|
|
782
|
+
body: { email, handle: options?.handle },
|
|
783
|
+
retry: "never"
|
|
784
|
+
});
|
|
709
785
|
return res.data;
|
|
710
786
|
}
|
|
787
|
+
/**
|
|
788
|
+
* Complete recovery by verifying the OTP. Returns the handle, the new API
|
|
789
|
+
* key, and an `AgentChatClient` already bound to it. **The key is shown
|
|
790
|
+
* only once — store it securely.**
|
|
791
|
+
*
|
|
792
|
+
* Throws `HandleRequiredError` when `recover()` ran without `handle` for
|
|
793
|
+
* an email that backs several agents; its `handles` lists them. The OTP
|
|
794
|
+
* is consumed either way — start over with `handle` set.
|
|
795
|
+
*/
|
|
711
796
|
static async recoverVerify(pendingId, code, options) {
|
|
712
797
|
const baseUrl = options?.baseUrl ?? DEFAULT_BASE_URL;
|
|
713
798
|
const http = new HttpTransport({
|
|
@@ -869,7 +954,7 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
869
954
|
* Mark one message as read for the caller. This updates that message's
|
|
870
955
|
* recipient envelope only; it does not implicitly mark earlier messages,
|
|
871
956
|
* so a conversation can legitimately contain unread gaps. A `message.read`
|
|
872
|
-
* event is fanned out to the sender
|
|
957
|
+
* event is fanned out to the sender over WebSocket.
|
|
873
958
|
*
|
|
874
959
|
* Realtime clients also have a WebSocket shortcut (`message.read_ack`
|
|
875
960
|
* frame) that bypasses this HTTP call. The REST method exists for
|
|
@@ -917,6 +1002,18 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
917
1002
|
opts
|
|
918
1003
|
);
|
|
919
1004
|
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Resolve direct-conversation continuity by peer handle before composing.
|
|
1007
|
+
* Returns `new`, `cold`, or `established`; this is strictly agent-to-agent
|
|
1008
|
+
* identity state between the authenticated agent and the peer agent.
|
|
1009
|
+
*/
|
|
1010
|
+
getDirectConversationContext(handle, opts) {
|
|
1011
|
+
const normalized = handle.replace(/^@/, "");
|
|
1012
|
+
return this.get(
|
|
1013
|
+
`/v1/conversations/direct/${encodeURIComponent(normalized)}/context`,
|
|
1014
|
+
opts
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
920
1017
|
/**
|
|
921
1018
|
* Hide a conversation from the caller's inbox (soft-delete, caller-scoped).
|
|
922
1019
|
* The other side's view is untouched — by design, matching the
|
|
@@ -1132,7 +1229,7 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
1132
1229
|
}
|
|
1133
1230
|
// ─── Mutes ────────────────────────────────────────────────────────────────
|
|
1134
1231
|
//
|
|
1135
|
-
// Mute suppresses real-time push
|
|
1232
|
+
// Mute suppresses real-time WebSocket push from a specific agent or
|
|
1136
1233
|
// conversation without blocking/leaving. Envelopes still land in
|
|
1137
1234
|
// `/v1/messages/sync` and the unread counter still bumps — the muter
|
|
1138
1235
|
// catches up on their own schedule. The sender sees a normal "delivered"
|
|
@@ -1255,23 +1352,6 @@ var AgentChatClient = class _AgentChatClient {
|
|
|
1255
1352
|
{ pageSize: options?.pageSize, max: options?.max }
|
|
1256
1353
|
);
|
|
1257
1354
|
}
|
|
1258
|
-
// ─── Webhooks ─────────────────────────────────────────────────────────────
|
|
1259
|
-
createWebhook(req, opts) {
|
|
1260
|
-
return this.post("/v1/webhooks", req, opts);
|
|
1261
|
-
}
|
|
1262
|
-
listWebhooks(opts) {
|
|
1263
|
-
return this.get("/v1/webhooks", opts);
|
|
1264
|
-
}
|
|
1265
|
-
/** Inspect a single webhook by id — shape mirrors an entry in `listWebhooks()`. */
|
|
1266
|
-
getWebhook(webhookId, opts) {
|
|
1267
|
-
return this.get(
|
|
1268
|
-
`/v1/webhooks/${encodeURIComponent(webhookId)}`,
|
|
1269
|
-
opts
|
|
1270
|
-
);
|
|
1271
|
-
}
|
|
1272
|
-
deleteWebhook(webhookId, opts) {
|
|
1273
|
-
return this.del(`/v1/webhooks/${encodeURIComponent(webhookId)}`, opts);
|
|
1274
|
-
}
|
|
1275
1355
|
// ─── Attachments ──────────────────────────────────────────────────────────
|
|
1276
1356
|
/**
|
|
1277
1357
|
* Request an attachment upload slot. The response includes a short-lived
|
|
@@ -1373,6 +1453,9 @@ Install the \`ws\` package if you're on Node 20 (Node 22+ has a native WebSocket
|
|
|
1373
1453
|
|
|
1374
1454
|
// src/realtime.ts
|
|
1375
1455
|
var HELLO_ACK_TIMEOUT_MS = 4e3;
|
|
1456
|
+
var STABLE_CONNECTION_MS = 3e4;
|
|
1457
|
+
var RAPID_RECONNECT_MS = 6e4;
|
|
1458
|
+
var INSTABILITY_WARN_THRESHOLD = 5;
|
|
1376
1459
|
var GAP_FILL_WINDOW_MS = 2e3;
|
|
1377
1460
|
var MAX_BUFFERED_PER_CONVERSATION = 500;
|
|
1378
1461
|
var GAP_FILL_LIMIT = 200;
|
|
@@ -1414,6 +1497,12 @@ var RealtimeClient = class {
|
|
|
1414
1497
|
connectHandlers = /* @__PURE__ */ new Set();
|
|
1415
1498
|
disconnectHandlers = /* @__PURE__ */ new Set();
|
|
1416
1499
|
reconnectAttempts = 0;
|
|
1500
|
+
/** Clears reconnectAttempts once this connection proves itself stable. */
|
|
1501
|
+
stabilityTimer = null;
|
|
1502
|
+
/** Consecutive connections that died before STABLE_CONNECTION_MS. Drives
|
|
1503
|
+
* the operator warning only; backoff itself uses reconnectAttempts. */
|
|
1504
|
+
rapidReconnects = 0;
|
|
1505
|
+
lastConnectAt = null;
|
|
1417
1506
|
reconnectTimer = null;
|
|
1418
1507
|
helloAckTimer = null;
|
|
1419
1508
|
authenticated = false;
|
|
@@ -1526,7 +1615,7 @@ var RealtimeClient = class {
|
|
|
1526
1615
|
this.authenticated = true;
|
|
1527
1616
|
const caps = message.capabilities;
|
|
1528
1617
|
this.ackMode = Array.isArray(caps) && caps.includes("ack");
|
|
1529
|
-
this.
|
|
1618
|
+
this.startStabilityTimer();
|
|
1530
1619
|
if (this.helloAckTimer) {
|
|
1531
1620
|
clearTimeout(this.helloAckTimer);
|
|
1532
1621
|
this.helloAckTimer = null;
|
|
@@ -1561,6 +1650,8 @@ var RealtimeClient = class {
|
|
|
1561
1650
|
clearTimeout(this.helloAckTimer);
|
|
1562
1651
|
this.helloAckTimer = null;
|
|
1563
1652
|
}
|
|
1653
|
+
this.cancelStabilityTimer();
|
|
1654
|
+
this.noteConnectionEnded();
|
|
1564
1655
|
this.authenticated = false;
|
|
1565
1656
|
this.ackMode = false;
|
|
1566
1657
|
const selfClosedForHelloTimeout = this.helloTimeoutClose;
|
|
@@ -1721,6 +1812,52 @@ var RealtimeClient = class {
|
|
|
1721
1812
|
const state = this.orderStates.get(row.conversation_id);
|
|
1722
1813
|
return state !== void 0 && state.buffer.has(row.seq);
|
|
1723
1814
|
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Clear the reconnect backoff once this connection proves itself.
|
|
1817
|
+
*
|
|
1818
|
+
* Scheduled on `hello.ok`, cancelled on close. If it fires, the socket
|
|
1819
|
+
* has been up for STABLE_CONNECTION_MS and the next failure deserves to
|
|
1820
|
+
* start from the floor again. If it is cancelled, the connection died
|
|
1821
|
+
* young and the counter carries forward, so the delay keeps ramping
|
|
1822
|
+
* toward the cap.
|
|
1823
|
+
*/
|
|
1824
|
+
startStabilityTimer() {
|
|
1825
|
+
this.cancelStabilityTimer();
|
|
1826
|
+
this.lastConnectAt = Date.now();
|
|
1827
|
+
this.stabilityTimer = setTimeout(() => {
|
|
1828
|
+
this.stabilityTimer = null;
|
|
1829
|
+
if (this.disposed || !this.authenticated) return;
|
|
1830
|
+
this.reconnectAttempts = 0;
|
|
1831
|
+
this.rapidReconnects = 0;
|
|
1832
|
+
}, STABLE_CONNECTION_MS);
|
|
1833
|
+
this.stabilityTimer.unref?.();
|
|
1834
|
+
}
|
|
1835
|
+
cancelStabilityTimer() {
|
|
1836
|
+
if (this.stabilityTimer) {
|
|
1837
|
+
clearTimeout(this.stabilityTimer);
|
|
1838
|
+
this.stabilityTimer = null;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Track short-lived connections and warn once they form a pattern.
|
|
1843
|
+
* A flapping client looks healthy from the inside — every reconnect
|
|
1844
|
+
* succeeds — so without this the operator has no local signal at all.
|
|
1845
|
+
*/
|
|
1846
|
+
noteConnectionEnded() {
|
|
1847
|
+
const started = this.lastConnectAt;
|
|
1848
|
+
this.lastConnectAt = null;
|
|
1849
|
+
if (started === null) return;
|
|
1850
|
+
if (Date.now() - started >= RAPID_RECONNECT_MS) {
|
|
1851
|
+
this.rapidReconnects = 0;
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
this.rapidReconnects++;
|
|
1855
|
+
if (this.rapidReconnects === INSTABILITY_WARN_THRESHOLD) {
|
|
1856
|
+
console.warn(
|
|
1857
|
+
`[agentchat] realtime connection is unstable: ${this.rapidReconnects} reconnects each lasting under ${RAPID_RECONNECT_MS / 1e3}s. Backing off (next retry in up to ${this.options.maxReconnectInterval / 1e3}s). This usually means the network path or a local supervisor is dropping the socket, not an AgentChat outage.`
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1724
1861
|
scheduleReconnect() {
|
|
1725
1862
|
if (this.disposed) return;
|
|
1726
1863
|
if (!this.options.reconnect) return;
|
|
@@ -1819,6 +1956,7 @@ var RealtimeClient = class {
|
|
|
1819
1956
|
clearTimeout(this.helloAckTimer);
|
|
1820
1957
|
this.helloAckTimer = null;
|
|
1821
1958
|
}
|
|
1959
|
+
this.cancelStabilityTimer();
|
|
1822
1960
|
this.drainAllPendingForShutdown();
|
|
1823
1961
|
try {
|
|
1824
1962
|
this.ws?.close();
|
|
@@ -2193,106 +2331,6 @@ var RealtimeClient = class {
|
|
|
2193
2331
|
}
|
|
2194
2332
|
};
|
|
2195
2333
|
|
|
2196
|
-
// src/webhook-verify.ts
|
|
2197
|
-
var WebhookVerificationError = class extends Error {
|
|
2198
|
-
reason;
|
|
2199
|
-
constructor(reason, message) {
|
|
2200
|
-
super(message ?? reason);
|
|
2201
|
-
this.name = "WebhookVerificationError";
|
|
2202
|
-
this.reason = reason;
|
|
2203
|
-
}
|
|
2204
|
-
};
|
|
2205
|
-
async function verifyWebhook(options) {
|
|
2206
|
-
const { payload, signature, secret, toleranceSeconds = 300 } = options;
|
|
2207
|
-
const now2 = options.now ?? Date.now;
|
|
2208
|
-
if (!signature) {
|
|
2209
|
-
throw new WebhookVerificationError("missing_signature");
|
|
2210
|
-
}
|
|
2211
|
-
const parsed = parseSignatureHeader(signature);
|
|
2212
|
-
const bodyString = typeof payload === "string" ? payload : new TextDecoder().decode(payload);
|
|
2213
|
-
let expectedMessage;
|
|
2214
|
-
if (parsed.timestamp !== null) {
|
|
2215
|
-
if (toleranceSeconds > 0) {
|
|
2216
|
-
const ageSeconds = Math.abs(now2() / 1e3 - parsed.timestamp);
|
|
2217
|
-
if (ageSeconds > toleranceSeconds) {
|
|
2218
|
-
throw new WebhookVerificationError("timestamp_skew");
|
|
2219
|
-
}
|
|
2220
|
-
}
|
|
2221
|
-
expectedMessage = `${parsed.timestamp}.${bodyString}`;
|
|
2222
|
-
} else {
|
|
2223
|
-
expectedMessage = bodyString;
|
|
2224
|
-
}
|
|
2225
|
-
const computed = await hmacSha256Hex(secret, expectedMessage);
|
|
2226
|
-
if (!constantTimeEqual(computed, parsed.digest)) {
|
|
2227
|
-
throw new WebhookVerificationError("bad_signature");
|
|
2228
|
-
}
|
|
2229
|
-
try {
|
|
2230
|
-
const json = JSON.parse(bodyString);
|
|
2231
|
-
return json;
|
|
2232
|
-
} catch {
|
|
2233
|
-
throw new WebhookVerificationError("malformed_payload");
|
|
2234
|
-
}
|
|
2235
|
-
}
|
|
2236
|
-
function parseSignatureHeader(header) {
|
|
2237
|
-
const trimmed = header.trim();
|
|
2238
|
-
if (trimmed.includes("=")) {
|
|
2239
|
-
const parts = trimmed.split(",");
|
|
2240
|
-
let timestamp = null;
|
|
2241
|
-
let digest2 = null;
|
|
2242
|
-
for (const p of parts) {
|
|
2243
|
-
const idx = p.indexOf("=");
|
|
2244
|
-
if (idx <= 0) continue;
|
|
2245
|
-
const key = p.slice(0, idx).trim();
|
|
2246
|
-
const value = p.slice(idx + 1).trim();
|
|
2247
|
-
if (key === "t") {
|
|
2248
|
-
const n = Number(value);
|
|
2249
|
-
if (Number.isFinite(n)) timestamp = n;
|
|
2250
|
-
} else if (key === "v1") {
|
|
2251
|
-
digest2 = value.toLowerCase();
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
if (!digest2 || !/^[a-f0-9]+$/.test(digest2)) {
|
|
2255
|
-
throw new WebhookVerificationError("malformed_signature");
|
|
2256
|
-
}
|
|
2257
|
-
return { timestamp, digest: digest2 };
|
|
2258
|
-
}
|
|
2259
|
-
const digest = trimmed.toLowerCase();
|
|
2260
|
-
if (!/^[a-f0-9]+$/.test(digest)) {
|
|
2261
|
-
throw new WebhookVerificationError("malformed_signature");
|
|
2262
|
-
}
|
|
2263
|
-
return { timestamp: null, digest };
|
|
2264
|
-
}
|
|
2265
|
-
async function hmacSha256Hex(secret, message) {
|
|
2266
|
-
const subtle = globalThis.crypto?.subtle;
|
|
2267
|
-
if (!subtle) {
|
|
2268
|
-
throw new WebhookVerificationError(
|
|
2269
|
-
"bad_signature",
|
|
2270
|
-
"Web Crypto API not available in this runtime; webhook verification requires `globalThis.crypto.subtle`."
|
|
2271
|
-
);
|
|
2272
|
-
}
|
|
2273
|
-
const enc = new TextEncoder();
|
|
2274
|
-
const key = await subtle.importKey(
|
|
2275
|
-
"raw",
|
|
2276
|
-
enc.encode(secret),
|
|
2277
|
-
{ name: "HMAC", hash: "SHA-256" },
|
|
2278
|
-
false,
|
|
2279
|
-
["sign"]
|
|
2280
|
-
);
|
|
2281
|
-
const sig = await subtle.sign("HMAC", key, enc.encode(message));
|
|
2282
|
-
const bytes = new Uint8Array(sig);
|
|
2283
|
-
let hex = "";
|
|
2284
|
-
for (const b of bytes) hex += b.toString(16).padStart(2, "0");
|
|
2285
|
-
return hex;
|
|
2286
|
-
}
|
|
2287
|
-
function constantTimeEqual(a, b) {
|
|
2288
|
-
if (a.length !== b.length) return false;
|
|
2289
|
-
let mismatch = 0;
|
|
2290
|
-
for (let i = 0; i < a.length; i++) {
|
|
2291
|
-
mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
2292
|
-
}
|
|
2293
|
-
return mismatch === 0;
|
|
2294
|
-
}
|
|
2295
|
-
|
|
2296
2334
|
// src/render.ts
|
|
2297
2335
|
var SEC = 1e3;
|
|
2298
2336
|
var MIN = 60 * SEC;
|
|
@@ -2363,6 +2401,6 @@ var ALLOWED_ATTACHMENT_MIME = [
|
|
|
2363
2401
|
"video/webm"
|
|
2364
2402
|
];
|
|
2365
2403
|
|
|
2366
|
-
export { ALLOWED_ATTACHMENT_MIME, AgentChatClient, AgentChatError, AwaitingReplyError, BlockedError, ConnectionError, DEFAULT_RETRY_POLICY, ErrorCode, ForbiddenError, GroupDeletedError, HttpTransport, MAX_ATTACHMENT_SIZE, NotFoundError, RateLimitedError, RealtimeClient, RecipientBackloggedError, RestrictedError, ServerError, SuspendedError, UnauthorizedError, VERSION, ValidationError,
|
|
2404
|
+
export { ALLOWED_ATTACHMENT_MIME, AgentChatClient, AgentChatError, AwaitingReplyError, BlockedError, ConnectionError, DEFAULT_RETRY_POLICY, EmailExhaustedError, EmailLimitReachedError, ErrorCode, ForbiddenError, GroupDeletedError, HandleRequiredError, HttpTransport, MAX_ATTACHMENT_SIZE, NotFoundError, RateLimitedError, RealtimeClient, RecipientBackloggedError, RestrictedError, ServerError, SuspendedError, UnauthorizedError, VERSION, ValidationError, createAgentChatError, paginate, parseRetryAfter, renderMessageContext };
|
|
2367
2405
|
//# sourceMappingURL=index.js.map
|
|
2368
2406
|
//# sourceMappingURL=index.js.map
|