@agentlair/sdk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -1,156 +1,432 @@
1
1
  /**
2
- * @agentlair/sdk — AgentLairClient
2
+ * @agentlair/sdk — AgentLair + AgentLairClient
3
3
  *
4
- * Official TypeScript/JavaScript SDK for AgentLair.
5
- * Zero dependencies. Works in Node 18, Bun, Deno, and modern browsers.
4
+ * `AgentLair` is the primary class. Accepts an API key string directly.
5
+ * `AgentLairClient` is the legacy class (accepts options object) still fully supported.
6
6
  *
7
- * @example
7
+ * @example Three-line onboarding
8
+ * const lair = new AgentLair(process.env.AGENTLAIR_API_KEY!);
9
+ * const inbox = await lair.email.claim('my-agent'); // auto-expands to my-agent@agentlair.dev
10
+ * const { messages } = await lair.email.inbox('my-agent@agentlair.dev');
11
+ *
12
+ * @example Full flow
8
13
  * // Create a new account (no API key needed)
9
- * const { api_key, account_id } = await AgentLairClient.createAccount({ name: 'my-agent' });
14
+ * const { api_key } = await AgentLair.createAccount({ name: 'my-agent' });
15
+ *
16
+ * const lair = new AgentLair(api_key);
17
+ * await lair.email.claim('my-agent');
18
+ * await lair.email.send({ from: 'my-agent@agentlair.dev', to: 'user@example.com', subject: 'Hello', text: 'Hi!' });
19
+ * const { messages } = await lair.email.inbox('my-agent@agentlair.dev');
10
20
  *
11
- * @example
12
- * // Use an existing key
13
- * const client = new AgentLairClient({ apiKey: process.env.AGENTLAIR_API_KEY! });
14
- * await client.claimAddress({ address: 'my-agent@agentlair.dev' });
15
- * await client.sendEmail({ from: 'my-agent@agentlair.dev', to: 'user@example.com', subject: 'Hello', text: 'Hi!' });
16
- * const inbox = await client.getInbox({ address: 'my-agent@agentlair.dev' });
21
+ * // Vault: store secrets (zero-knowledge — use @agentlair/vault-crypto to encrypt first)
22
+ * await lair.vault.put('openai-key', { ciphertext: encryptedBlob });
23
+ * const { ciphertext } = await lair.vault.get('openai-key');
17
24
  */
18
25
  import { AgentLairError } from './errors.js';
19
26
  const DEFAULT_BASE_URL = 'https://agentlair.dev';
20
- // ─── VaultNamespace ───────────────────────────────────────────────────────────
27
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
21
28
  /**
22
- * vault.put / vault.get / vault.list / vault.delete
23
- *
24
- * The AgentLair Vault is a zero-knowledge secret store.
25
- * The server stores opaque encrypted blobs — plaintext never leaves your client.
26
- * Use @agentlair/vault-crypto for client-side encryption helpers.
29
+ * Expand a short name like "my-agent" to "my-agent@agentlair.dev".
30
+ * If the address already contains "@", returns it as-is.
27
31
  */
28
- class VaultNamespace {
29
- _request;
30
- constructor(_request) {
31
- this._request = _request;
32
+ function expandAddress(address) {
33
+ return address.includes('@') ? address : `${address}@agentlair.dev`;
34
+ }
35
+ // ─── Internal request helper (shared by both classes) ─────────────────────────
36
+ async function makeRequest(baseUrl, apiKey, method, path, opts = {}) {
37
+ const url = new URL(baseUrl + path);
38
+ if (opts.query) {
39
+ for (const [k, v] of Object.entries(opts.query)) {
40
+ url.searchParams.set(k, v);
41
+ }
42
+ }
43
+ const headers = {
44
+ 'Content-Type': 'application/json',
45
+ };
46
+ if (opts.auth !== null) {
47
+ headers['Authorization'] = `Bearer ${opts.auth ?? apiKey}`;
48
+ }
49
+ const response = await fetch(url.toString(), {
50
+ method,
51
+ headers,
52
+ body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
53
+ });
54
+ let data;
55
+ const contentType = response.headers.get('content-type') ?? '';
56
+ if (contentType.includes('application/json')) {
57
+ data = await response.json();
58
+ }
59
+ else {
60
+ data = await response.text();
61
+ }
62
+ if (!response.ok) {
63
+ const body = data;
64
+ throw new AgentLairError(body?.message ?? `HTTP ${response.status}`, response.status, body?.error ?? 'error');
65
+ }
66
+ return data;
67
+ }
68
+ // ─── WebhooksNamespace ────────────────────────────────────────────────────────
69
+ class WebhooksNamespace {
70
+ _req;
71
+ constructor(_req) {
72
+ this._req = _req;
32
73
  }
33
74
  /**
34
- * Store an encrypted blob in the Vault.
75
+ * Register a webhook URL to receive real-time `email.received` events.
35
76
  *
36
- * Each PUT creates a new version (append-only, versioned).
37
- * Free tier: up to 50 keys, 3 versions each.
77
+ * @example
78
+ * const hook = await lair.email.webhooks.create({
79
+ * address: 'my-agent@agentlair.dev',
80
+ * url: 'https://myserver.com/webhook',
81
+ * secret: 'my-secret',
82
+ * });
83
+ */
84
+ async create(options) {
85
+ return this._req('POST', '/v1/email/webhooks', {
86
+ body: { ...options, address: expandAddress(options.address) },
87
+ });
88
+ }
89
+ /**
90
+ * List registered webhooks, optionally filtered by address.
38
91
  *
39
92
  * @example
40
- * // With @agentlair/vault-crypto:
41
- * const vc = VaultCrypto.fromSeed(seed);
42
- * const ciphertext = await vc.encrypt('sk-openai-...', 'openai-key');
43
- * await client.vault.put('openai-key', { ciphertext });
93
+ * const { webhooks } = await lair.email.webhooks.list();
44
94
  */
45
- async put(key, options) {
46
- return this._request('PUT', `/v1/vault/${encodeURIComponent(key)}`, {
47
- body: options,
95
+ async list(options = {}) {
96
+ const query = {};
97
+ if (options.address)
98
+ query.address = expandAddress(options.address);
99
+ return this._req('GET', '/v1/email/webhooks', { query });
100
+ }
101
+ /**
102
+ * Delete a webhook by ID.
103
+ *
104
+ * @example
105
+ * await lair.email.webhooks.delete('wh_abc123');
106
+ */
107
+ async delete(id) {
108
+ return this._req('DELETE', `/v1/email/webhooks/${encodeURIComponent(id)}`);
109
+ }
110
+ }
111
+ // ─── EmailNamespace ───────────────────────────────────────────────────────────
112
+ class EmailNamespace {
113
+ _req;
114
+ /** Webhook management: webhooks.create / webhooks.list / webhooks.delete */
115
+ webhooks;
116
+ constructor(_req) {
117
+ this._req = _req;
118
+ this.webhooks = new WebhooksNamespace(_req);
119
+ }
120
+ /**
121
+ * Claim an @agentlair.dev email address.
122
+ *
123
+ * Pass a short name (e.g. `"my-agent"`) and it auto-expands to `my-agent@agentlair.dev`.
124
+ *
125
+ * @example
126
+ * await lair.email.claim('my-agent'); // → my-agent@agentlair.dev
127
+ * await lair.email.claim('my-agent@agentlair.dev'); // also works
128
+ */
129
+ async claim(address, options = {}) {
130
+ return this._req('POST', '/v1/email/claim', {
131
+ body: { ...options, address: expandAddress(address) },
48
132
  });
49
133
  }
50
134
  /**
51
- * Retrieve an encrypted blob from the Vault.
135
+ * List all @agentlair.dev addresses claimed by this account.
136
+ *
137
+ * @example
138
+ * const { addresses } = await lair.email.addresses();
139
+ */
140
+ async addresses() {
141
+ return this._req('GET', '/v1/email/addresses');
142
+ }
143
+ /**
144
+ * Get inbox messages (previews — no full body).
145
+ * Use `read()` for the full body of a specific message.
52
146
  *
53
- * Returns the latest version by default. Pass `version` for a specific one.
147
+ * @example
148
+ * const { messages } = await lair.email.inbox('my-agent@agentlair.dev');
149
+ * const { messages } = await lair.email.inbox('my-agent', { limit: 5 });
150
+ */
151
+ async inbox(address, options = {}) {
152
+ const query = { address: expandAddress(address) };
153
+ if (options.limit !== undefined)
154
+ query.limit = String(options.limit);
155
+ return this._req('GET', '/v1/email/inbox', { query });
156
+ }
157
+ /**
158
+ * Read the full body of a message. Marks as read.
159
+ *
160
+ * @example
161
+ * const msg = await lair.email.read(inboxMsg.message_id_url, 'my-agent@agentlair.dev');
162
+ * console.log(msg.body);
163
+ */
164
+ async read(messageId, address) {
165
+ return this._req('GET', `/v1/email/messages/${messageId}`, { query: { address: expandAddress(address) } });
166
+ }
167
+ /**
168
+ * Delete a message.
54
169
  *
55
170
  * @example
56
- * const { ciphertext } = await client.vault.get('openai-key');
57
- * // With @agentlair/vault-crypto:
58
- * const plaintext = await vc.decrypt(ciphertext, 'openai-key');
171
+ * await lair.email.deleteMessage(inboxMsg.message_id_url, 'my-agent@agentlair.dev');
172
+ */
173
+ async deleteMessage(messageId, address) {
174
+ return this._req('DELETE', `/v1/email/messages/${messageId}`, { query: { address: expandAddress(address) } });
175
+ }
176
+ /**
177
+ * Update message properties (mark read/unread).
178
+ *
179
+ * @example
180
+ * await lair.email.update(msg.message_id_url, 'my-agent@agentlair.dev', { read: false });
181
+ */
182
+ async update(messageId, address, options) {
183
+ return this._req('PATCH', `/v1/email/messages/${messageId}`, { query: { address: expandAddress(address) }, body: options });
184
+ }
185
+ /**
186
+ * Send an email from an address you own.
187
+ *
188
+ * @example
189
+ * await lair.email.send({
190
+ * from: 'my-agent@agentlair.dev',
191
+ * to: 'user@example.com',
192
+ * subject: 'Hello',
193
+ * text: 'Hi from an AI agent!',
194
+ * });
195
+ */
196
+ async send(options) {
197
+ return this._req('POST', '/v1/email/send', { body: options });
198
+ }
199
+ /**
200
+ * List sent messages (outbox).
201
+ *
202
+ * @example
203
+ * const { messages } = await lair.email.outbox({ limit: 5 });
204
+ */
205
+ async outbox(options = {}) {
206
+ const query = {};
207
+ if (options.limit !== undefined)
208
+ query.limit = String(options.limit);
209
+ return this._req('GET', '/v1/email/outbox', { query });
210
+ }
211
+ }
212
+ // ─── VaultNamespace ───────────────────────────────────────────────────────────
213
+ /**
214
+ * Zero-knowledge secret store.
215
+ * Server stores opaque encrypted blobs — plaintext never leaves your client.
216
+ * Use @agentlair/vault-crypto for client-side encryption.
217
+ */
218
+ class VaultNamespace {
219
+ _req;
220
+ constructor(_req) {
221
+ this._req = _req;
222
+ }
223
+ /**
224
+ * Store an encrypted blob (versioned, append-only).
225
+ *
226
+ * @example
227
+ * await lair.vault.put('openai-key', { ciphertext: encryptedBlob });
228
+ */
229
+ async put(key, options) {
230
+ return this._req('PUT', `/v1/vault/${encodeURIComponent(key)}`, { body: options });
231
+ }
232
+ /**
233
+ * Retrieve an encrypted blob. Returns latest version by default.
234
+ *
235
+ * @example
236
+ * const { ciphertext } = await lair.vault.get('openai-key');
237
+ * const old = await lair.vault.get('openai-key', { version: 1 });
59
238
  */
60
239
  async get(key, options = {}) {
61
240
  const query = {};
62
241
  if (options.version !== undefined)
63
242
  query.version = String(options.version);
64
- return this._request('GET', `/v1/vault/${encodeURIComponent(key)}`, { query });
243
+ return this._req('GET', `/v1/vault/${encodeURIComponent(key)}`, { query });
65
244
  }
66
245
  /**
67
- * List all Vault keys for this account (metadata only — no ciphertext).
246
+ * List all Vault keys (metadata only).
68
247
  *
69
248
  * @example
70
- * const { keys, count, limit } = await client.vault.list();
249
+ * const { keys, count, limit } = await lair.vault.list();
71
250
  */
72
251
  async list() {
73
- return this._request('GET', '/v1/vault/');
252
+ return this._req('GET', '/v1/vault/');
74
253
  }
75
254
  /**
76
- * Delete a Vault key (all versions) or a specific version.
77
- *
78
- * Pass `version` to delete only that version. Omit to delete all versions.
255
+ * Delete a key (all versions) or a specific version.
79
256
  *
80
257
  * @example
81
- * await client.vault.delete('openai-key'); // delete all versions
82
- * await client.vault.delete('openai-key', { version: 2 }); // delete v2 only
258
+ * await lair.vault.delete('openai-key');
259
+ * await lair.vault.delete('openai-key', { version: 2 });
83
260
  */
84
261
  async delete(key, options = {}) {
85
262
  const query = {};
86
263
  if (options.version !== undefined)
87
264
  query.version = String(options.version);
88
- return this._request('DELETE', `/v1/vault/${encodeURIComponent(key)}`, {
89
- query,
90
- });
265
+ return this._req('DELETE', `/v1/vault/${encodeURIComponent(key)}`, { query });
91
266
  }
92
267
  }
93
- // ─── AgentLairClient ──────────────────────────────────────────────────────────
94
- export class AgentLairClient {
268
+ // ─── StacksNamespace ──────────────────────────────────────────────────────────
269
+ class StacksNamespace {
270
+ _req;
271
+ constructor(_req) {
272
+ this._req = _req;
273
+ }
274
+ /**
275
+ * Create a domain stack. Points nameservers to AgentLair DNS.
276
+ * Beta: DNS provisioning is stubbed. Full CF DNS integration coming Q2 2026.
277
+ *
278
+ * @example
279
+ * const stack = await lair.stacks.create({ domain: 'myagent.dev' });
280
+ */
281
+ async create(options) {
282
+ return this._req('POST', '/v1/stack', { body: options });
283
+ }
284
+ /**
285
+ * List all domain stacks for this account.
286
+ *
287
+ * @example
288
+ * const { stacks } = await lair.stacks.list();
289
+ */
290
+ async list() {
291
+ return this._req('GET', '/v1/stack');
292
+ }
293
+ }
294
+ // ─── ObservationsNamespace ────────────────────────────────────────────────────
295
+ class ObservationsNamespace {
296
+ _req;
297
+ constructor(_req) {
298
+ this._req = _req;
299
+ }
300
+ /**
301
+ * Write a structured observation. Account-scoped by default.
302
+ * Set `shared: true` to make visible to all authenticated agents.
303
+ *
304
+ * @example
305
+ * await lair.observations.write({ topic: 'market-signals', content: 'BTC up 5%' });
306
+ */
307
+ async write(options) {
308
+ return this._req('POST', '/v1/observations', { body: options });
309
+ }
310
+ /**
311
+ * Read observations. Returns own + shared by default.
312
+ *
313
+ * @example
314
+ * const { observations } = await lair.observations.read({ topic: 'market-signals' });
315
+ * const shared = await lair.observations.read({ scope: 'shared' });
316
+ */
317
+ async read(options = {}) {
318
+ const query = {};
319
+ if (options.topic)
320
+ query.topic = options.topic;
321
+ if (options.agent_id)
322
+ query.agent_id = options.agent_id;
323
+ if (options.since)
324
+ query.since = options.since;
325
+ if (options.scope)
326
+ query.scope = options.scope;
327
+ if (options.limit !== undefined)
328
+ query.limit = String(options.limit);
329
+ return this._req('GET', '/v1/observations', { query });
330
+ }
331
+ /**
332
+ * List distinct topics with observation count.
333
+ *
334
+ * @example
335
+ * const { topics } = await lair.observations.topics();
336
+ */
337
+ async topics() {
338
+ return this._req('GET', '/v1/observations/topics');
339
+ }
340
+ }
341
+ // ─── AccountNamespace ─────────────────────────────────────────────────────────
342
+ class AccountNamespace {
343
+ _req;
344
+ constructor(_req) {
345
+ this._req = _req;
346
+ }
347
+ /**
348
+ * Get the current account profile.
349
+ *
350
+ * @example
351
+ * const { account_id, tier } = await lair.account.me();
352
+ */
353
+ async me() {
354
+ return this._req('GET', '/v1/account/me');
355
+ }
356
+ /**
357
+ * Get current usage statistics.
358
+ *
359
+ * @example
360
+ * const { emails } = await lair.account.usage();
361
+ * console.log(emails.daily_remaining);
362
+ */
363
+ async usage() {
364
+ return this._req('GET', '/v1/usage');
365
+ }
366
+ /**
367
+ * Get billing information.
368
+ *
369
+ * @example
370
+ * const billing = await lair.account.billing();
371
+ */
372
+ async billing() {
373
+ return this._req('GET', '/v1/billing');
374
+ }
375
+ }
376
+ // ─── AgentLair (primary class) ────────────────────────────────────────────────
377
+ /**
378
+ * AgentLair — primary SDK class.
379
+ *
380
+ * Accepts an API key string directly (or an options object for advanced config).
381
+ *
382
+ * @example Three-line onboarding
383
+ * const lair = new AgentLair(process.env.AGENTLAIR_API_KEY!);
384
+ * const inbox = await lair.email.claim('my-agent');
385
+ * const { messages } = await lair.email.inbox('my-agent@agentlair.dev');
386
+ */
387
+ export class AgentLair {
95
388
  _apiKey;
96
389
  _baseUrl;
390
+ /** Email: claim / inbox / send / read / deleteMessage / update / outbox / addresses / webhooks */
391
+ email;
392
+ /** Vault: put / get / list / delete */
393
+ vault;
394
+ /** Stacks: create / list */
395
+ stacks;
396
+ /** Observations: write / read / topics */
397
+ observations;
398
+ /** Account: me / usage / billing */
399
+ account;
97
400
  /**
98
- * Namespaced Vault operations: vault.put / vault.get / vault.list / vault.delete
401
+ * @param apiKeyOrOptions API key string (e.g. "al_live_...") or options object
99
402
  */
100
- vault;
101
- constructor(options) {
102
- this._apiKey = options.apiKey;
103
- this._baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
104
- this.vault = new VaultNamespace(this._request.bind(this));
105
- }
106
- // ─── Internal request helper ─────────────────────────────────────────────
107
- async _request(method, path, opts = {}) {
108
- const url = new URL(this._baseUrl + path);
109
- if (opts.query) {
110
- for (const [k, v] of Object.entries(opts.query)) {
111
- url.searchParams.set(k, v);
112
- }
113
- }
114
- const headers = {
115
- 'Content-Type': 'application/json',
116
- };
117
- // auth defaults to Bearer <apiKey>; pass null to skip auth
118
- if (opts.auth !== null) {
119
- headers['Authorization'] = `Bearer ${opts.auth ?? this._apiKey}`;
120
- }
121
- const response = await fetch(url.toString(), {
122
- method,
123
- headers,
124
- body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
125
- });
126
- let data;
127
- const contentType = response.headers.get('content-type') ?? '';
128
- if (contentType.includes('application/json')) {
129
- data = await response.json();
403
+ constructor(apiKeyOrOptions) {
404
+ if (typeof apiKeyOrOptions === 'string') {
405
+ this._apiKey = apiKeyOrOptions;
406
+ this._baseUrl = DEFAULT_BASE_URL;
130
407
  }
131
408
  else {
132
- data = await response.text();
133
- }
134
- if (!response.ok) {
135
- const body = data;
136
- throw new AgentLairError(body?.message ?? `HTTP ${response.status}`, response.status, body?.error ?? 'error');
409
+ this._apiKey = apiKeyOrOptions.apiKey;
410
+ this._baseUrl = (apiKeyOrOptions.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
137
411
  }
138
- return data;
412
+ const req = this._request.bind(this);
413
+ this.email = new EmailNamespace(req);
414
+ this.vault = new VaultNamespace(req);
415
+ this.stacks = new StacksNamespace(req);
416
+ this.observations = new ObservationsNamespace(req);
417
+ this.account = new AccountNamespace(req);
139
418
  }
140
- // ─── Static: createAccount ───────────────────────────────────────────────
419
+ _request(method, path, opts = {}) {
420
+ return makeRequest(this._baseUrl, this._apiKey, method, path, opts);
421
+ }
422
+ // ─── Static: createAccount ─────────────────────────────────────────────────
141
423
  /**
142
424
  * Create a new AgentLair account and get an API key.
143
- *
144
- * No existing account or API key needed — this is the bootstrapping method.
145
- * **Save the returned `api_key` immediately** — it will not be shown again.
146
- *
147
- * @param options Optional name and recovery email
148
- * @param baseUrl Override API base URL (default: https://agentlair.dev)
425
+ * No existing account needed. **Save the returned `api_key` immediately** — not shown again.
149
426
  *
150
427
  * @example
151
- * const { api_key, account_id } = await AgentLairClient.createAccount({ name: 'my-agent' });
152
- * // Store api_key securely — never log it
153
- * const client = new AgentLairClient({ apiKey: api_key });
428
+ * const { api_key } = await AgentLair.createAccount({ name: 'my-agent' });
429
+ * const lair = new AgentLair(api_key);
154
430
  */
155
431
  static async createAccount(options = {}, baseUrl = DEFAULT_BASE_URL) {
156
432
  const url = baseUrl.replace(/\/$/, '') + '/v1/auth/keys';
@@ -165,77 +441,58 @@ export class AgentLairClient {
165
441
  }
166
442
  return data;
167
443
  }
168
- // ─── Email: claimAddress ─────────────────────────────────────────────────
169
- /**
170
- * Claim an @agentlair.dev email address for this account.
171
- *
172
- * First-touch ownership model the first agent to claim an address owns it.
173
- * DKIM, SPF, and DMARC are pre-configured. Ready to send in under 5 seconds.
174
- *
175
- * Optionally provide a `public_key` (base64url X25519, 32 bytes) to enable
176
- * end-to-end encryption for inbound messages.
177
- *
178
- * @example
179
- * await client.claimAddress({ address: 'my-agent@agentlair.dev' });
180
- */
444
+ }
445
+ // ─── AgentLairClient (legacy — fully backward compatible) ─────────────────────
446
+ /**
447
+ * @deprecated Use `AgentLair` instead — simpler string constructor, same namespaces.
448
+ * `AgentLairClient` is fully retained for backward compatibility.
449
+ */
450
+ export class AgentLairClient {
451
+ _apiKey;
452
+ _baseUrl;
453
+ /** Vault: put / get / list / delete */
454
+ vault;
455
+ /** Email: claim / inbox / send / read / outbox / addresses / webhooks */
456
+ email;
457
+ /** Stacks: create / list */
458
+ stacks;
459
+ /** Observations: write / read / topics */
460
+ observations;
461
+ /** Account: me / usage / billing */
462
+ account;
463
+ constructor(options) {
464
+ this._apiKey = options.apiKey;
465
+ this._baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, '');
466
+ const req = this._request.bind(this);
467
+ this.vault = new VaultNamespace(req);
468
+ this.email = new EmailNamespace(req);
469
+ this.stacks = new StacksNamespace(req);
470
+ this.observations = new ObservationsNamespace(req);
471
+ this.account = new AccountNamespace(req);
472
+ }
473
+ _request(method, path, opts = {}) {
474
+ return makeRequest(this._baseUrl, this._apiKey, method, path, opts);
475
+ }
476
+ /** @deprecated Prefer `AgentLair.createAccount()` */
477
+ static async createAccount(options = {}, baseUrl = DEFAULT_BASE_URL) {
478
+ return AgentLair.createAccount(options, baseUrl);
479
+ }
480
+ // ─── Legacy flat methods (backward compatible) ────────────────────────────
481
+ /** @deprecated Use `client.email.claim(address)` */
181
482
  async claimAddress(options) {
182
- return this._request('POST', '/v1/email/claim', { body: options });
483
+ return this.email.claim(options.address, { public_key: options.public_key });
183
484
  }
184
- // ─── Email: sendEmail ────────────────────────────────────────────────────
185
- /**
186
- * Send a DKIM-signed email from an @agentlair.dev address you own.
187
- *
188
- * Supports plain text, HTML, or both. Supports threading via `in_reply_to`.
189
- * Free tier: 10 emails/day per address.
190
- *
191
- * @example
192
- * await client.sendEmail({
193
- * from: 'my-agent@agentlair.dev',
194
- * to: 'user@example.com',
195
- * subject: 'Hello from AgentLair',
196
- * text: 'Hi! This email was sent by an AI agent.',
197
- * });
198
- */
485
+ /** @deprecated Use `client.email.send(options)` */
199
486
  async sendEmail(options) {
200
- return this._request('POST', '/v1/email/send', { body: options });
487
+ return this.email.send(options);
201
488
  }
202
- // ─── Email: getInbox ─────────────────────────────────────────────────────
203
- /**
204
- * Get the inbox for an @agentlair.dev address you own.
205
- *
206
- * Returns message previews (no full body). Use `readMessage()` for the full body.
207
- *
208
- * @example
209
- * const { messages, count } = await client.getInbox({ address: 'my-agent@agentlair.dev' });
210
- * for (const msg of messages) {
211
- * console.log(msg.from, msg.subject, msg.snippet);
212
- * }
213
- */
489
+ /** @deprecated Use `client.email.inbox(address, options)` */
214
490
  async getInbox(options) {
215
- const query = { address: options.address };
216
- if (options.limit !== undefined)
217
- query.limit = String(options.limit);
218
- return this._request('GET', '/v1/email/inbox', { query });
491
+ return this.email.inbox(options.address, { limit: options.limit });
219
492
  }
220
- // ─── Email: readMessage ──────────────────────────────────────────────────
221
- /**
222
- * Read the full body of a specific message.
223
- *
224
- * Marks the message as read. For E2E-encrypted messages, returns
225
- * `ciphertext` and `ephemeral_public_key` for client-side decryption.
226
- *
227
- * @param messageId Use `message_id_url` from inbox (URL-encoded) or raw `message_id`
228
- * @param address The @agentlair.dev address that received the message
229
- *
230
- * @example
231
- * const msg = await client.readMessage({
232
- * messageId: inboxMsg.message_id_url,
233
- * address: 'my-agent@agentlair.dev',
234
- * });
235
- * console.log(msg.body);
236
- */
493
+ /** @deprecated Use `client.email.read(messageId, address)` */
237
494
  async readMessage(options) {
238
- return this._request('GET', `/v1/email/messages/${options.messageId}`, { query: { address: options.address } });
495
+ return this.email.read(options.messageId, options.address);
239
496
  }
240
497
  }
241
498
  //# sourceMappingURL=client.js.map