agentmail 0.5.34 → 0.5.36
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/cjs/BaseClient.js +2 -2
- package/dist/cjs/api/resources/apps/client/Client.js +7 -1
- package/dist/cjs/api/resources/apps/client/requests/ListAppsRequest.d.ts +2 -0
- package/dist/cjs/api/resources/apps/types/App.d.ts +2 -0
- package/dist/cjs/api/resources/apps/types/AppCategory.d.ts +20 -0
- package/dist/cjs/api/resources/apps/types/AppCategory.js +23 -0
- package/dist/cjs/api/resources/apps/types/index.d.ts +1 -0
- package/dist/cjs/api/resources/apps/types/index.js +1 -0
- package/dist/cjs/api/resources/inboxes/client/Client.d.ts +4 -0
- package/dist/cjs/api/resources/inboxes/client/Client.js +12 -0
- package/dist/cjs/api/resources/inboxes/types/CreateInboxRequest.d.ts +2 -0
- package/dist/cjs/api/resources/inboxes/types/Inbox.d.ts +6 -0
- package/dist/cjs/api/resources/inboxes/types/InboxStatus.d.ts +11 -0
- package/dist/cjs/api/resources/inboxes/types/InboxStatus.js +14 -0
- package/dist/cjs/api/resources/inboxes/types/UpdateInboxRequest.d.ts +8 -2
- package/dist/cjs/api/resources/inboxes/types/index.d.ts +1 -0
- package/dist/cjs/api/resources/inboxes/types/index.js +1 -0
- package/dist/cjs/api/resources/pods/resources/inboxes/client/Client.d.ts +1 -0
- package/dist/cjs/api/resources/pods/resources/inboxes/client/Client.js +9 -0
- package/dist/cjs/serialization/resources/apps/types/App.d.ts +2 -0
- package/dist/cjs/serialization/resources/apps/types/App.js +2 -0
- package/dist/cjs/serialization/resources/apps/types/AppCategory.d.ts +7 -0
- package/dist/cjs/serialization/resources/apps/types/AppCategory.js +56 -0
- package/dist/cjs/serialization/resources/apps/types/index.d.ts +1 -0
- package/dist/cjs/serialization/resources/apps/types/index.js +1 -0
- package/dist/cjs/serialization/resources/inboxes/types/CreateInboxRequest.d.ts +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/CreateInboxRequest.js +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/Inbox.d.ts +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/Inbox.js +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/InboxStatus.d.ts +7 -0
- package/dist/cjs/serialization/resources/inboxes/types/InboxStatus.js +39 -0
- package/dist/cjs/serialization/resources/inboxes/types/UpdateInboxRequest.d.ts +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/UpdateInboxRequest.js +2 -0
- package/dist/cjs/serialization/resources/inboxes/types/index.d.ts +1 -0
- package/dist/cjs/serialization/resources/inboxes/types/index.js +1 -0
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/wrapper/WebsocketsClient.d.ts +15 -1
- package/dist/cjs/wrapper/WebsocketsClient.js +26 -8
- package/dist/cjs/wrapper/reconnect.d.ts +22 -0
- package/dist/cjs/wrapper/reconnect.js +246 -0
- package/dist/esm/BaseClient.mjs +2 -2
- package/dist/esm/api/resources/apps/client/Client.mjs +7 -1
- package/dist/esm/api/resources/apps/client/requests/ListAppsRequest.d.mts +2 -0
- package/dist/esm/api/resources/apps/types/App.d.mts +2 -0
- package/dist/esm/api/resources/apps/types/AppCategory.d.mts +20 -0
- package/dist/esm/api/resources/apps/types/AppCategory.mjs +20 -0
- package/dist/esm/api/resources/apps/types/index.d.mts +1 -0
- package/dist/esm/api/resources/apps/types/index.mjs +1 -0
- package/dist/esm/api/resources/inboxes/client/Client.d.mts +4 -0
- package/dist/esm/api/resources/inboxes/client/Client.mjs +12 -0
- package/dist/esm/api/resources/inboxes/types/CreateInboxRequest.d.mts +2 -0
- package/dist/esm/api/resources/inboxes/types/Inbox.d.mts +6 -0
- package/dist/esm/api/resources/inboxes/types/InboxStatus.d.mts +11 -0
- package/dist/esm/api/resources/inboxes/types/InboxStatus.mjs +11 -0
- package/dist/esm/api/resources/inboxes/types/UpdateInboxRequest.d.mts +8 -2
- package/dist/esm/api/resources/inboxes/types/index.d.mts +1 -0
- package/dist/esm/api/resources/inboxes/types/index.mjs +1 -0
- package/dist/esm/api/resources/pods/resources/inboxes/client/Client.d.mts +1 -0
- package/dist/esm/api/resources/pods/resources/inboxes/client/Client.mjs +9 -0
- package/dist/esm/serialization/resources/apps/types/App.d.mts +2 -0
- package/dist/esm/serialization/resources/apps/types/App.mjs +2 -0
- package/dist/esm/serialization/resources/apps/types/AppCategory.d.mts +7 -0
- package/dist/esm/serialization/resources/apps/types/AppCategory.mjs +20 -0
- package/dist/esm/serialization/resources/apps/types/index.d.mts +1 -0
- package/dist/esm/serialization/resources/apps/types/index.mjs +1 -0
- package/dist/esm/serialization/resources/inboxes/types/CreateInboxRequest.d.mts +2 -0
- package/dist/esm/serialization/resources/inboxes/types/CreateInboxRequest.mjs +2 -0
- package/dist/esm/serialization/resources/inboxes/types/Inbox.d.mts +2 -0
- package/dist/esm/serialization/resources/inboxes/types/Inbox.mjs +2 -0
- package/dist/esm/serialization/resources/inboxes/types/InboxStatus.d.mts +7 -0
- package/dist/esm/serialization/resources/inboxes/types/InboxStatus.mjs +3 -0
- package/dist/esm/serialization/resources/inboxes/types/UpdateInboxRequest.d.mts +2 -0
- package/dist/esm/serialization/resources/inboxes/types/UpdateInboxRequest.mjs +2 -0
- package/dist/esm/serialization/resources/inboxes/types/index.d.mts +1 -0
- package/dist/esm/serialization/resources/inboxes/types/index.mjs +1 -0
- package/dist/esm/version.d.mts +1 -1
- package/dist/esm/version.mjs +1 -1
- package/dist/esm/wrapper/WebsocketsClient.d.mts +15 -1
- package/dist/esm/wrapper/WebsocketsClient.mjs +26 -8
- package/dist/esm/wrapper/reconnect.d.mts +22 -0
- package/dist/esm/wrapper/reconnect.mjs +208 -0
- package/package.json +1 -1
- package/reference.md +3 -0
|
@@ -57,31 +57,49 @@ exports.WebsocketsClient = void 0;
|
|
|
57
57
|
const Client_js_1 = require("../api/resources/websockets/client/Client.js");
|
|
58
58
|
const core = __importStar(require("../core/index.js"));
|
|
59
59
|
const environments = __importStar(require("../environments.js"));
|
|
60
|
+
const version_js_1 = require("../version.js");
|
|
61
|
+
const reconnect_js_1 = require("./reconnect.js");
|
|
62
|
+
// The generated client's default. Always passed explicitly: auto-reconnect has to know the generated
|
|
63
|
+
// socket's exact retry budget to take over before it runs out.
|
|
64
|
+
const DEFAULT_RECONNECT_ATTEMPTS = 30;
|
|
65
|
+
// Lets the server tell SDK releases apart on the handshake (Node only; browsers cannot set handshake
|
|
66
|
+
// headers). Caller-supplied headers win.
|
|
67
|
+
const SDK_HEADERS = { "X-Fern-SDK-Name": "agentmail", "X-Fern-SDK-Version": version_js_1.SDK_VERSION };
|
|
60
68
|
class WebsocketsClient extends Client_js_1.WebsocketsClient {
|
|
61
|
-
constructor(options, getPaymentCredentials) {
|
|
69
|
+
constructor(options, getPaymentCredentials, reconnectPolicy = reconnect_js_1.DEFAULT_RECONNECT_POLICY) {
|
|
62
70
|
super(options);
|
|
63
71
|
this._getPaymentCredentials = getPaymentCredentials;
|
|
72
|
+
this._reconnectPolicy = reconnectPolicy;
|
|
64
73
|
}
|
|
65
74
|
connect() {
|
|
66
75
|
const _super = Object.create(null, {
|
|
67
76
|
connect: { get: () => super.connect }
|
|
68
77
|
});
|
|
69
78
|
return __awaiter(this, arguments, void 0, function* (args = {}) {
|
|
70
|
-
var _a, _b, _c;
|
|
71
|
-
const { waitForOpen = true } = args, rest = __rest(args, ["waitForOpen"]);
|
|
72
|
-
|
|
79
|
+
var _a, _b, _c, _d;
|
|
80
|
+
const { waitForOpen = true, autoReconnect = true } = args, rest = __rest(args, ["waitForOpen", "autoReconnect"]);
|
|
81
|
+
const reconnectAttempts = (_a = rest.reconnectAttempts) !== null && _a !== void 0 ? _a : DEFAULT_RECONNECT_ATTEMPTS;
|
|
82
|
+
let connectArgs = Object.assign(Object.assign({}, rest), { reconnectAttempts, headers: Object.assign(Object.assign({}, SDK_HEADERS), rest.headers) });
|
|
73
83
|
if (this._getPaymentCredentials) {
|
|
74
|
-
const wsUrl = core.url.join((
|
|
84
|
+
const wsUrl = core.url.join((_b = (yield core.Supplier.get(this._options.baseUrl))) !== null && _b !== void 0 ? _b : ((_c = (yield core.Supplier.get(this._options.environment))) !== null && _c !== void 0 ? _c : environments.AgentMailEnvironment.Prod)
|
|
85
|
+
.websockets, "/v0");
|
|
75
86
|
const credentials = yield this._getPaymentCredentials(wsUrl);
|
|
76
|
-
connectArgs = Object.assign(Object.assign({},
|
|
87
|
+
connectArgs = Object.assign(Object.assign({}, connectArgs), { queryParams: Object.assign(Object.assign({}, credentials), rest.queryParams) });
|
|
77
88
|
}
|
|
78
89
|
else if (!rest.apiKey) {
|
|
79
|
-
const apiKey = (
|
|
80
|
-
connectArgs = Object.assign(Object.assign({},
|
|
90
|
+
const apiKey = (_d = (yield core.Supplier.get(this._options.apiKey))) !== null && _d !== void 0 ? _d : process.env.AGENTMAIL_API_KEY;
|
|
91
|
+
connectArgs = Object.assign(Object.assign({}, connectArgs), { apiKey });
|
|
81
92
|
}
|
|
82
93
|
const socket = yield _super.connect.call(this, connectArgs);
|
|
83
94
|
if (waitForOpen)
|
|
84
95
|
yield socket.waitForOpen();
|
|
96
|
+
if (autoReconnect && reconnectAttempts > 0) {
|
|
97
|
+
(0, reconnect_js_1.enableAutoReconnect)(socket, {
|
|
98
|
+
maxRetries: reconnectAttempts,
|
|
99
|
+
abortSignal: rest.abortSignal,
|
|
100
|
+
policy: this._reconnectPolicy,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
85
103
|
return socket;
|
|
86
104
|
});
|
|
87
105
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WebsocketsSocket } from "../api/resources/websockets/client/Socket.js";
|
|
2
|
+
export interface ReconnectPolicy {
|
|
3
|
+
baseDelayMs: number;
|
|
4
|
+
maxDelayMs: number;
|
|
5
|
+
/** How long a connection must stay open before the backoff starts over. */
|
|
6
|
+
stableAfterMs: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const DEFAULT_RECONNECT_POLICY: ReconnectPolicy;
|
|
9
|
+
/** Exponential backoff with full jitter: uniform in [0, min(maxDelayMs, baseDelayMs * 2^attempt)). */
|
|
10
|
+
export declare function backoffDelay(attempt: number, policy: ReconnectPolicy, random?: () => number): number;
|
|
11
|
+
export interface AutoReconnectOptions {
|
|
12
|
+
/** The generated socket's own retry budget (`reconnectAttempts`). */
|
|
13
|
+
maxRetries: number;
|
|
14
|
+
abortSignal?: AbortSignal;
|
|
15
|
+
policy: ReconnectPolicy;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Keeps `socket` connected and subscribed: re-sends every subscription on each reconnect, takes over
|
|
19
|
+
* reconnecting whenever the generated socket gives up, and stops on close(), abort, or a terminal
|
|
20
|
+
* handshake refusal.
|
|
21
|
+
*/
|
|
22
|
+
export declare function enableAutoReconnect(socket: WebsocketsSocket, options: AutoReconnectOptions): void;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
36
|
+
var t = {};
|
|
37
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
38
|
+
t[p] = s[p];
|
|
39
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
40
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
41
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
42
|
+
t[p[i]] = s[p[i]];
|
|
43
|
+
}
|
|
44
|
+
return t;
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.DEFAULT_RECONNECT_POLICY = void 0;
|
|
48
|
+
exports.backoffDelay = backoffDelay;
|
|
49
|
+
exports.enableAutoReconnect = enableAutoReconnect;
|
|
50
|
+
const index_js_1 = require("../core/index.js");
|
|
51
|
+
const Events = __importStar(require("../core/websocket/events.js"));
|
|
52
|
+
exports.DEFAULT_RECONNECT_POLICY = { baseDelayMs: 1000, maxDelayMs: 60000, stableAfterMs: 5000 };
|
|
53
|
+
/** Exponential backoff with full jitter: uniform in [0, min(maxDelayMs, baseDelayMs * 2^attempt)). */
|
|
54
|
+
function backoffDelay(attempt, policy, random = Math.random) {
|
|
55
|
+
return random() * Math.min(policy.maxDelayMs, policy.baseDelayMs * Math.pow(2, attempt));
|
|
56
|
+
}
|
|
57
|
+
const { OPEN, CLOSING, CLOSED } = index_js_1.ReconnectingWebSocket.ReadyState;
|
|
58
|
+
// ws reports a refused handshake as "Unexpected server response: <status>". Browsers expose no status,
|
|
59
|
+
// so there every refusal looks transient and is retried on the capped backoff.
|
|
60
|
+
const HANDSHAKE_STATUS = /^Unexpected server response: (\d{3})\b/;
|
|
61
|
+
// Refusals that retrying with the same credentials cannot fix. 402 comes from the x402/MPP proxies,
|
|
62
|
+
// whose payment credential is minted once per connect() call and reused on reconnects. The server
|
|
63
|
+
// also answers 403 when the organization is at its connection cap, which a retry could outlast.
|
|
64
|
+
const TERMINAL_FAILURES = new Map([
|
|
65
|
+
["401", "WebSocket authentication failed (401): the API key is missing, invalid, or was deleted."],
|
|
66
|
+
[
|
|
67
|
+
"402",
|
|
68
|
+
"WebSocket payment required (402): the payment credential minted by connect() is no longer accepted; open a new socket with client.websockets.connect() to pay again.",
|
|
69
|
+
],
|
|
70
|
+
[
|
|
71
|
+
"403",
|
|
72
|
+
"WebSocket authentication failed (403): the API key is invalid or was deleted, or the organization is at its WebSocket connection limit.",
|
|
73
|
+
],
|
|
74
|
+
]);
|
|
75
|
+
/**
|
|
76
|
+
* Keeps `socket` connected and subscribed: re-sends every subscription on each reconnect, takes over
|
|
77
|
+
* reconnecting whenever the generated socket gives up, and stops on close(), abort, or a terminal
|
|
78
|
+
* handshake refusal.
|
|
79
|
+
*/
|
|
80
|
+
function enableAutoReconnect(socket, options) {
|
|
81
|
+
const { maxRetries, abortSignal, policy } = options;
|
|
82
|
+
const rws = socket.socket;
|
|
83
|
+
const sendSubscribe = socket.sendSubscribe.bind(socket);
|
|
84
|
+
const closeSocket = rws.close.bind(rws);
|
|
85
|
+
const reconnectSocket = rws.reconnect.bind(rws);
|
|
86
|
+
// Keyed by canonical JSON, in the order last sent. The server keeps one subscription per target and
|
|
87
|
+
// the last filter sent for it, so a new message takes its targets out of every earlier one: a
|
|
88
|
+
// replay can never put back a filter the caller has since changed.
|
|
89
|
+
const subscriptions = new Map();
|
|
90
|
+
// Keys already sent on the current connection, e.g. by the user's own open handler.
|
|
91
|
+
const sentOnConnection = new Set();
|
|
92
|
+
let opened = rws.readyState === OPEN;
|
|
93
|
+
let openedAt = opened ? Date.now() : undefined;
|
|
94
|
+
let stopped = false;
|
|
95
|
+
let attempt = 0;
|
|
96
|
+
let timer;
|
|
97
|
+
let emitting = false;
|
|
98
|
+
const isStopped = () => stopped || (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) === true;
|
|
99
|
+
const cancelTimer = () => {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
timer = undefined;
|
|
102
|
+
};
|
|
103
|
+
const stop = () => {
|
|
104
|
+
stopped = true;
|
|
105
|
+
cancelTimer();
|
|
106
|
+
};
|
|
107
|
+
const emitError = (message) => {
|
|
108
|
+
var _a;
|
|
109
|
+
const event = new Events.ErrorEvent(new Error(message), rws);
|
|
110
|
+
emitting = true;
|
|
111
|
+
try {
|
|
112
|
+
(_a = rws.onerror) === null || _a === void 0 ? void 0 : _a.call(rws, event);
|
|
113
|
+
rws.dispatchEvent(event);
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
emitting = false;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const scheduleReconnect = () => {
|
|
120
|
+
cancelTimer();
|
|
121
|
+
timer = setTimeout(() => {
|
|
122
|
+
timer = undefined;
|
|
123
|
+
if (isStopped())
|
|
124
|
+
return;
|
|
125
|
+
// reconnect() on a socket that is not CLOSED closes it with 1000 and then never connects.
|
|
126
|
+
if (rws.readyState === CLOSED)
|
|
127
|
+
reconnectSocket();
|
|
128
|
+
else if (rws.readyState === CLOSING)
|
|
129
|
+
scheduleReconnect();
|
|
130
|
+
}, backoffDelay(attempt++, policy));
|
|
131
|
+
};
|
|
132
|
+
rws.addEventListener("open", () => {
|
|
133
|
+
cancelTimer();
|
|
134
|
+
openedAt = Date.now();
|
|
135
|
+
if (!opened) {
|
|
136
|
+
opened = true;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
for (const [key, message] of subscriptions) {
|
|
140
|
+
if (isStopped() || rws.readyState !== OPEN)
|
|
141
|
+
return;
|
|
142
|
+
if (sentOnConnection.has(key))
|
|
143
|
+
continue;
|
|
144
|
+
try {
|
|
145
|
+
sendSubscribe(message);
|
|
146
|
+
sentOnConnection.add(key);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
emitError(`Failed to re-subscribe after reconnecting: ${error instanceof Error ? error.message : String(error)}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
rws.addEventListener("close", (event) => {
|
|
154
|
+
sentOnConnection.clear();
|
|
155
|
+
if (openedAt !== undefined && Date.now() - openedAt >= policy.stableAfterMs)
|
|
156
|
+
attempt = 0;
|
|
157
|
+
openedAt = undefined;
|
|
158
|
+
if (isStopped())
|
|
159
|
+
return;
|
|
160
|
+
if (event.code !== 1000) {
|
|
161
|
+
// The generated socket retries these closes itself, up to maxRetries times.
|
|
162
|
+
if (rws.retryCount < maxRetries)
|
|
163
|
+
return;
|
|
164
|
+
// It has just scheduled its last retry. If that one fails too, it keeps its connect lock
|
|
165
|
+
// and ignores reconnect() for good, so cancel it and take over.
|
|
166
|
+
closeSocket();
|
|
167
|
+
}
|
|
168
|
+
scheduleReconnect();
|
|
169
|
+
});
|
|
170
|
+
rws.addEventListener("error", (event) => {
|
|
171
|
+
var _a;
|
|
172
|
+
if (emitting || isStopped())
|
|
173
|
+
return;
|
|
174
|
+
const status = (_a = HANDSHAKE_STATUS.exec(event.message)) === null || _a === void 0 ? void 0 : _a[1];
|
|
175
|
+
const failure = status === undefined ? undefined : TERMINAL_FAILURES.get(status);
|
|
176
|
+
if (failure === undefined)
|
|
177
|
+
return;
|
|
178
|
+
stop();
|
|
179
|
+
emitError(`${failure} Not reconnecting.`);
|
|
180
|
+
});
|
|
181
|
+
abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.addEventListener("abort", stop, { once: true });
|
|
182
|
+
// Patched on the generated socket so WebsocketsSocket.close()/connect() and direct
|
|
183
|
+
// socket.socket.close()/reconnect() calls all count as the user's intent.
|
|
184
|
+
rws.close = (code, reason) => {
|
|
185
|
+
stop();
|
|
186
|
+
subscriptions.clear();
|
|
187
|
+
closeSocket(code, reason);
|
|
188
|
+
};
|
|
189
|
+
rws.reconnect = (code, reason) => {
|
|
190
|
+
stopped = false;
|
|
191
|
+
attempt = 0;
|
|
192
|
+
cancelTimer();
|
|
193
|
+
reconnectSocket(code, reason);
|
|
194
|
+
};
|
|
195
|
+
socket.sendSubscribe = (message) => {
|
|
196
|
+
sendSubscribe(message);
|
|
197
|
+
const recorded = JSON.parse(JSON.stringify(message));
|
|
198
|
+
const covered = new Set(targetsOf(recorded));
|
|
199
|
+
const kept = [...subscriptions].flatMap(([key, cached]) => {
|
|
200
|
+
const remaining = withoutTargets(cached, covered);
|
|
201
|
+
if (remaining === undefined)
|
|
202
|
+
return [];
|
|
203
|
+
return [[remaining === cached ? key : subscriptionKey(remaining), remaining]];
|
|
204
|
+
});
|
|
205
|
+
const key = subscriptionKey(recorded);
|
|
206
|
+
subscriptions.clear();
|
|
207
|
+
for (const [keptKey, keptMessage] of kept)
|
|
208
|
+
if (keptKey !== key)
|
|
209
|
+
subscriptions.set(keptKey, keptMessage);
|
|
210
|
+
subscriptions.set(key, recorded);
|
|
211
|
+
sentOnConnection.add(key);
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// What a subscribe message sets on the server: one subscription per inbox and per pod it names, or the
|
|
215
|
+
// credential's own scope when it names neither. That default resolves server-side to an inbox, pod or
|
|
216
|
+
// organization the SDK cannot see, so it is tracked as its own target.
|
|
217
|
+
function targetsOf(message) {
|
|
218
|
+
var _a, _b;
|
|
219
|
+
if (message.inboxIds === undefined && message.podIds === undefined)
|
|
220
|
+
return ["default"];
|
|
221
|
+
return [...((_a = message.inboxIds) !== null && _a !== void 0 ? _a : []).map((id) => `inbox:${id}`), ...((_b = message.podIds) !== null && _b !== void 0 ? _b : []).map((id) => `pod:${id}`)];
|
|
222
|
+
}
|
|
223
|
+
// `message` without the covered targets; undefined once none of its targets is left.
|
|
224
|
+
function withoutTargets(message, covered) {
|
|
225
|
+
const targets = targetsOf(message);
|
|
226
|
+
if (!targets.some((target) => covered.has(target)))
|
|
227
|
+
return message;
|
|
228
|
+
if (targets.every((target) => covered.has(target)))
|
|
229
|
+
return undefined;
|
|
230
|
+
const { inboxIds, podIds } = message, rest = __rest(message, ["inboxIds", "podIds"]);
|
|
231
|
+
const keptInboxIds = inboxIds === null || inboxIds === void 0 ? void 0 : inboxIds.filter((id) => !covered.has(`inbox:${id}`));
|
|
232
|
+
const keptPodIds = podIds === null || podIds === void 0 ? void 0 : podIds.filter((id) => !covered.has(`pod:${id}`));
|
|
233
|
+
return Object.assign(Object.assign(Object.assign({}, rest), ((keptInboxIds === null || keptInboxIds === void 0 ? void 0 : keptInboxIds.length) ? { inboxIds: keptInboxIds } : {})), ((keptPodIds === null || keptPodIds === void 0 ? void 0 : keptPodIds.length) ? { podIds: keptPodIds } : {}));
|
|
234
|
+
}
|
|
235
|
+
// Canonical JSON (sorted object keys), so the same subscription written in a different key order dedupes.
|
|
236
|
+
function subscriptionKey(message) {
|
|
237
|
+
return JSON.stringify(message, (_key, value) => {
|
|
238
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
239
|
+
return value;
|
|
240
|
+
const sorted = {};
|
|
241
|
+
for (const key of Object.keys(value).sort()) {
|
|
242
|
+
sorted[key] = value[key];
|
|
243
|
+
}
|
|
244
|
+
return sorted;
|
|
245
|
+
});
|
|
246
|
+
}
|
package/dist/esm/BaseClient.mjs
CHANGED
|
@@ -6,8 +6,8 @@ export function normalizeClientOptions(options) {
|
|
|
6
6
|
const headers = mergeHeaders({
|
|
7
7
|
"X-Fern-Language": "JavaScript",
|
|
8
8
|
"X-Fern-SDK-Name": "agentmail",
|
|
9
|
-
"X-Fern-SDK-Version": "0.5.
|
|
10
|
-
"User-Agent": "agentmail/0.5.
|
|
9
|
+
"X-Fern-SDK-Version": "0.5.36",
|
|
10
|
+
"User-Agent": "agentmail/0.5.36",
|
|
11
11
|
"X-Fern-Runtime": core.RUNTIME.type,
|
|
12
12
|
"X-Fern-Runtime-Version": core.RUNTIME.version,
|
|
13
13
|
}, options === null || options === void 0 ? void 0 : options.headers);
|
|
@@ -37,10 +37,16 @@ export class AppsClient {
|
|
|
37
37
|
__list() {
|
|
38
38
|
return __awaiter(this, arguments, void 0, function* (request = {}, requestOptions) {
|
|
39
39
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
40
|
-
const { limit, pageToken } = request;
|
|
40
|
+
const { limit, pageToken, category } = request;
|
|
41
41
|
const _queryParams = {
|
|
42
42
|
limit,
|
|
43
43
|
page_token: pageToken,
|
|
44
|
+
category: category != null
|
|
45
|
+
? serializers.AppCategory.jsonOrThrow(category, {
|
|
46
|
+
unrecognizedObjectKeys: "strip",
|
|
47
|
+
omitUndefined: true,
|
|
48
|
+
})
|
|
49
|
+
: undefined,
|
|
44
50
|
};
|
|
45
51
|
const _authRequest = yield this._options.authProvider.getAuthRequest();
|
|
46
52
|
const _headers = mergeHeaders(_authRequest.headers, (_a = this._options) === null || _a === void 0 ? void 0 : _a.headers, requestOptions === null || requestOptions === void 0 ? void 0 : requestOptions.headers);
|
|
@@ -6,4 +6,6 @@ import type * as AgentMail from "../../../../index.mjs";
|
|
|
6
6
|
export interface ListAppsRequest {
|
|
7
7
|
limit?: AgentMail.Limit;
|
|
8
8
|
pageToken?: AgentMail.PageToken;
|
|
9
|
+
/** Only apps in this category. A filtered page can hold fewer than `limit` apps while more remain, so page until `next_page_token` is absent. A `page_token` works only with the `category` it was returned for. */
|
|
10
|
+
category?: AgentMail.AppCategory;
|
|
9
11
|
}
|
|
@@ -11,6 +11,8 @@ export interface App {
|
|
|
11
11
|
logoUrl?: string;
|
|
12
12
|
termsUrl?: string;
|
|
13
13
|
privacyUrl?: string;
|
|
14
|
+
/** Kinds of app, up to 3. Omitted when the app sets none. */
|
|
15
|
+
categories?: AgentMail.AppCategory[];
|
|
14
16
|
/** Maximum number of accounts your organization may sign up at this app. Omitted when the app sets no limit. 0 means the app has paused new sign-ups; existing accounts keep signing in. */
|
|
15
17
|
ownerSignupLimit?: number;
|
|
16
18
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Kind of app. */
|
|
2
|
+
export declare const AppCategory: {
|
|
3
|
+
readonly Ai: "ai";
|
|
4
|
+
readonly Search: "search";
|
|
5
|
+
readonly Scraping: "scraping";
|
|
6
|
+
readonly Browser: "browser";
|
|
7
|
+
readonly Data: "data";
|
|
8
|
+
readonly DeveloperTools: "developer-tools";
|
|
9
|
+
readonly Communication: "communication";
|
|
10
|
+
readonly Productivity: "productivity";
|
|
11
|
+
readonly Payments: "payments";
|
|
12
|
+
readonly Finance: "finance";
|
|
13
|
+
readonly Commerce: "commerce";
|
|
14
|
+
readonly Marketing: "marketing";
|
|
15
|
+
readonly Analytics: "analytics";
|
|
16
|
+
readonly Security: "security";
|
|
17
|
+
readonly Infrastructure: "infrastructure";
|
|
18
|
+
readonly Other: "other";
|
|
19
|
+
};
|
|
20
|
+
export type AppCategory = (typeof AppCategory)[keyof typeof AppCategory];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
/** Kind of app. */
|
|
3
|
+
export const AppCategory = {
|
|
4
|
+
Ai: "ai",
|
|
5
|
+
Search: "search",
|
|
6
|
+
Scraping: "scraping",
|
|
7
|
+
Browser: "browser",
|
|
8
|
+
Data: "data",
|
|
9
|
+
DeveloperTools: "developer-tools",
|
|
10
|
+
Communication: "communication",
|
|
11
|
+
Productivity: "productivity",
|
|
12
|
+
Payments: "payments",
|
|
13
|
+
Finance: "finance",
|
|
14
|
+
Commerce: "commerce",
|
|
15
|
+
Marketing: "marketing",
|
|
16
|
+
Analytics: "analytics",
|
|
17
|
+
Security: "security",
|
|
18
|
+
Infrastructure: "infrastructure",
|
|
19
|
+
Other: "other",
|
|
20
|
+
};
|
|
@@ -110,12 +110,16 @@ export declare class InboxesClient {
|
|
|
110
110
|
* agentmail inboxes update --inbox-id <inbox_id> --display-name "Updated Name"
|
|
111
111
|
* ```
|
|
112
112
|
*
|
|
113
|
+
* To pause an inbox, set `status` to `paused`; set it back to `active` to
|
|
114
|
+
* resume. See [Pausing an inbox](/inboxes#pausing-an-inbox).
|
|
115
|
+
*
|
|
113
116
|
* @param {AgentMail.inboxes.InboxId} inbox_id
|
|
114
117
|
* @param {AgentMail.inboxes.UpdateInboxRequest} request
|
|
115
118
|
* @param {InboxesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
116
119
|
*
|
|
117
120
|
* @throws {@link AgentMail.NotFoundError}
|
|
118
121
|
* @throws {@link AgentMail.ValidationError}
|
|
122
|
+
* @throws {@link AgentMail.ConflictError}
|
|
119
123
|
*
|
|
120
124
|
* @example
|
|
121
125
|
* await client.inboxes.update("inbox_id", {})
|
|
@@ -357,12 +357,16 @@ export class InboxesClient {
|
|
|
357
357
|
* agentmail inboxes update --inbox-id <inbox_id> --display-name "Updated Name"
|
|
358
358
|
* ```
|
|
359
359
|
*
|
|
360
|
+
* To pause an inbox, set `status` to `paused`; set it back to `active` to
|
|
361
|
+
* resume. See [Pausing an inbox](/inboxes#pausing-an-inbox).
|
|
362
|
+
*
|
|
360
363
|
* @param {AgentMail.inboxes.InboxId} inbox_id
|
|
361
364
|
* @param {AgentMail.inboxes.UpdateInboxRequest} request
|
|
362
365
|
* @param {InboxesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
363
366
|
*
|
|
364
367
|
* @throws {@link AgentMail.NotFoundError}
|
|
365
368
|
* @throws {@link AgentMail.ValidationError}
|
|
369
|
+
* @throws {@link AgentMail.ConflictError}
|
|
366
370
|
*
|
|
367
371
|
* @example
|
|
368
372
|
* await client.inboxes.update("inbox_id", {})
|
|
@@ -423,6 +427,14 @@ export class InboxesClient {
|
|
|
423
427
|
skipValidation: true,
|
|
424
428
|
breadcrumbsPrefix: ["response"],
|
|
425
429
|
}), _response.rawResponse);
|
|
430
|
+
case 409:
|
|
431
|
+
throw new AgentMail.ConflictError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
|
|
432
|
+
unrecognizedObjectKeys: "passthrough",
|
|
433
|
+
allowUnrecognizedUnionMembers: true,
|
|
434
|
+
allowUnrecognizedEnumValues: true,
|
|
435
|
+
skipValidation: true,
|
|
436
|
+
breadcrumbsPrefix: ["response"],
|
|
437
|
+
}), _response.rawResponse);
|
|
426
438
|
default:
|
|
427
439
|
throw new errors.AgentMailError({
|
|
428
440
|
statusCode: _response.error.statusCode,
|
|
@@ -10,6 +10,8 @@ export interface CreateInboxRequest {
|
|
|
10
10
|
domain?: string;
|
|
11
11
|
displayName?: AgentMail.inboxes.DisplayName;
|
|
12
12
|
clientId?: AgentMail.inboxes.ClientId;
|
|
13
|
+
/** Set `paused` to create the inbox paused. */
|
|
14
|
+
status?: AgentMail.inboxes.InboxStatus;
|
|
13
15
|
/** Custom metadata to attach to the inbox. */
|
|
14
16
|
metadata?: AgentMail.inboxes.Metadata;
|
|
15
17
|
}
|
|
@@ -5,6 +5,12 @@ export interface Inbox {
|
|
|
5
5
|
email: AgentMail.inboxes.Email;
|
|
6
6
|
displayName?: AgentMail.inboxes.DisplayName;
|
|
7
7
|
clientId?: AgentMail.inboxes.ClientId;
|
|
8
|
+
/**
|
|
9
|
+
* `paused` when the inbox is paused. Omitted when the inbox is active.
|
|
10
|
+
* Treat any value other than `paused` as an inbox that sends and
|
|
11
|
+
* receives normally.
|
|
12
|
+
*/
|
|
13
|
+
status?: AgentMail.inboxes.InboxStatus;
|
|
8
14
|
/** Custom metadata attached to the inbox. */
|
|
9
15
|
metadata?: AgentMail.inboxes.Metadata;
|
|
10
16
|
/** Time at which inbox was last updated. */
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the inbox sends and receives mail. `paused` stops both: sends
|
|
3
|
+
* return `403` with code `inbox_paused`, and incoming mail is not
|
|
4
|
+
* delivered and not bounced, then or on resume. Mail already in the inbox,
|
|
5
|
+
* its drafts, and its API keys are kept. Set `active` to resume.
|
|
6
|
+
*/
|
|
7
|
+
export declare const InboxStatus: {
|
|
8
|
+
readonly Active: "active";
|
|
9
|
+
readonly Paused: "paused";
|
|
10
|
+
};
|
|
11
|
+
export type InboxStatus = (typeof InboxStatus)[keyof typeof InboxStatus];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// This file was auto-generated by Fern from our API Definition.
|
|
2
|
+
/**
|
|
3
|
+
* Whether the inbox sends and receives mail. `paused` stops both: sends
|
|
4
|
+
* return `403` with code `inbox_paused`, and incoming mail is not
|
|
5
|
+
* delivered and not bounced, then or on resume. Mail already in the inbox,
|
|
6
|
+
* its drafts, and its API keys are kept. Set `active` to resume.
|
|
7
|
+
*/
|
|
8
|
+
export const InboxStatus = {
|
|
9
|
+
Active: "active",
|
|
10
|
+
Paused: "paused",
|
|
11
|
+
};
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import type * as AgentMail from "../../../index.mjs";
|
|
2
2
|
export interface UpdateInboxRequest {
|
|
3
3
|
displayName?: AgentMail.inboxes.DisplayName;
|
|
4
|
+
/**
|
|
5
|
+
* `paused` stops the inbox sending and receiving mail; `active` resumes
|
|
6
|
+
* it. Mail that arrived while the inbox was paused is not delivered on
|
|
7
|
+
* resume.
|
|
8
|
+
*/
|
|
9
|
+
status?: AgentMail.inboxes.InboxStatus;
|
|
4
10
|
/**
|
|
5
11
|
* Metadata to merge into the inbox's existing metadata. Keys you include
|
|
6
12
|
* are added or overwritten; keys you omit are left unchanged. To remove a
|
|
7
13
|
* single key, send it with a null value. To clear all metadata, send
|
|
8
14
|
* `metadata` as null. Sending an empty object is rejected; use null to
|
|
9
|
-
* clear. Each update must include at least one of `display_name
|
|
10
|
-
* `metadata`.
|
|
15
|
+
* clear. Each update must include at least one of `display_name`,
|
|
16
|
+
* `status`, or `metadata`.
|
|
11
17
|
*/
|
|
12
18
|
metadata?: AgentMail.inboxes.UpdateMetadata | null;
|
|
13
19
|
}
|
|
@@ -6,6 +6,7 @@ export * from "./DisplayName.mjs";
|
|
|
6
6
|
export * from "./Email.mjs";
|
|
7
7
|
export * from "./Inbox.mjs";
|
|
8
8
|
export * from "./InboxId.mjs";
|
|
9
|
+
export * from "./InboxStatus.mjs";
|
|
9
10
|
export * from "./ListInboxesResponse.mjs";
|
|
10
11
|
export * from "./Metadata.mjs";
|
|
11
12
|
export * from "./MetadataValue.mjs";
|
|
@@ -6,6 +6,7 @@ export * from "./DisplayName.mjs";
|
|
|
6
6
|
export * from "./Email.mjs";
|
|
7
7
|
export * from "./Inbox.mjs";
|
|
8
8
|
export * from "./InboxId.mjs";
|
|
9
|
+
export * from "./InboxStatus.mjs";
|
|
9
10
|
export * from "./ListInboxesResponse.mjs";
|
|
10
11
|
export * from "./Metadata.mjs";
|
|
11
12
|
export * from "./MetadataValue.mjs";
|
|
@@ -96,6 +96,7 @@ export declare class InboxesClient {
|
|
|
96
96
|
* @param {InboxesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
97
97
|
*
|
|
98
98
|
* @throws {@link AgentMail.NotFoundError}
|
|
99
|
+
* @throws {@link AgentMail.ConflictError}
|
|
99
100
|
*
|
|
100
101
|
* @example
|
|
101
102
|
* await client.pods.inboxes.update("pod_id", "inbox_id", {})
|
|
@@ -344,6 +344,7 @@ export class InboxesClient {
|
|
|
344
344
|
* @param {InboxesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
345
345
|
*
|
|
346
346
|
* @throws {@link AgentMail.NotFoundError}
|
|
347
|
+
* @throws {@link AgentMail.ConflictError}
|
|
347
348
|
*
|
|
348
349
|
* @example
|
|
349
350
|
* await client.pods.inboxes.update("pod_id", "inbox_id", {})
|
|
@@ -396,6 +397,14 @@ export class InboxesClient {
|
|
|
396
397
|
skipValidation: true,
|
|
397
398
|
breadcrumbsPrefix: ["response"],
|
|
398
399
|
}), _response.rawResponse);
|
|
400
|
+
case 409:
|
|
401
|
+
throw new AgentMail.ConflictError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
|
|
402
|
+
unrecognizedObjectKeys: "passthrough",
|
|
403
|
+
allowUnrecognizedUnionMembers: true,
|
|
404
|
+
allowUnrecognizedEnumValues: true,
|
|
405
|
+
skipValidation: true,
|
|
406
|
+
breadcrumbsPrefix: ["response"],
|
|
407
|
+
}), _response.rawResponse);
|
|
399
408
|
default:
|
|
400
409
|
throw new errors.AgentMailError({
|
|
401
410
|
statusCode: _response.error.statusCode,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type * as AgentMail from "../../../../api/index.mjs";
|
|
2
2
|
import * as core from "../../../../core/index.mjs";
|
|
3
3
|
import type * as serializers from "../../../index.mjs";
|
|
4
|
+
import { AppCategory } from "./AppCategory.mjs";
|
|
4
5
|
import { AppId } from "./AppId.mjs";
|
|
5
6
|
export declare const App: core.serialization.ObjectSchema<serializers.App.Raw, AgentMail.App>;
|
|
6
7
|
export declare namespace App {
|
|
@@ -12,6 +13,7 @@ export declare namespace App {
|
|
|
12
13
|
logo_url?: string | null;
|
|
13
14
|
terms_url?: string | null;
|
|
14
15
|
privacy_url?: string | null;
|
|
16
|
+
categories?: AppCategory.Raw[] | null;
|
|
15
17
|
owner_signup_limit?: number | null;
|
|
16
18
|
}
|
|
17
19
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// This file was auto-generated by Fern from our API Definition.
|
|
2
2
|
import * as core from "../../../../core/index.mjs";
|
|
3
|
+
import { AppCategory } from "./AppCategory.mjs";
|
|
3
4
|
import { AppId } from "./AppId.mjs";
|
|
4
5
|
export const App = core.serialization.object({
|
|
5
6
|
appId: core.serialization.property("app_id", AppId),
|
|
@@ -9,5 +10,6 @@ export const App = core.serialization.object({
|
|
|
9
10
|
logoUrl: core.serialization.property("logo_url", core.serialization.string().optional()),
|
|
10
11
|
termsUrl: core.serialization.property("terms_url", core.serialization.string().optional()),
|
|
11
12
|
privacyUrl: core.serialization.property("privacy_url", core.serialization.string().optional()),
|
|
13
|
+
categories: core.serialization.list(AppCategory).optional(),
|
|
12
14
|
ownerSignupLimit: core.serialization.property("owner_signup_limit", core.serialization.number().optional()),
|
|
13
15
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type * as AgentMail from "../../../../api/index.mjs";
|
|
2
|
+
import * as core from "../../../../core/index.mjs";
|
|
3
|
+
import type * as serializers from "../../../index.mjs";
|
|
4
|
+
export declare const AppCategory: core.serialization.Schema<serializers.AppCategory.Raw, AgentMail.AppCategory>;
|
|
5
|
+
export declare namespace AppCategory {
|
|
6
|
+
type Raw = "ai" | "search" | "scraping" | "browser" | "data" | "developer-tools" | "communication" | "productivity" | "payments" | "finance" | "commerce" | "marketing" | "analytics" | "security" | "infrastructure" | "other";
|
|
7
|
+
}
|