@pidgeon-ai/sdk 1.14.0 → 1.16.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/CHANGELOG.md +27 -1
- package/README.md +80 -19
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -2
- package/dist/index.d.ts +117 -2
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/package.json +11 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,33 @@ the two would publish a release for every unrelated product deploy.
|
|
|
7
7
|
Semver applies to **this package's own surface** — the exported names, the
|
|
8
8
|
call shapes, the result shape — not to the API behind it.
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## 1.16.0 — an attachment as text
|
|
11
|
+
|
|
12
|
+
`attachmentsText` (`GET /attachments/{id}/text`) returns a text attachment —
|
|
13
|
+
CSV, log, JSON, calendar — as text, up to 5 MB and 200,000 characters, with
|
|
14
|
+
a Pidgeon Firewall verdict judged with the message's sender. `body: 'clean'`
|
|
15
|
+
returns the cleaned text. HTML, PDF, Office files and images are refused.
|
|
16
|
+
|
|
17
|
+
## 1.15.0 — a read says what it held back
|
|
18
|
+
|
|
19
|
+
`GET /messages/await` returns `held_back`: matching messages that arrived
|
|
20
|
+
and were filed as spam, by count and id, so a wait that times out on a code
|
|
21
|
+
from a sender whose authentication failed no longer reads as "nothing came".
|
|
22
|
+
`include_spam=true` returns such a message instead. The inbox page of
|
|
23
|
+
`GET /mailboxes/{folder}` carries `held_back.spam`, the unread messages in
|
|
24
|
+
Spam, because an inbox that looks empty may not be.
|
|
25
|
+
|
|
26
|
+
## 1.14.2 — the PyPI page is the Python README
|
|
27
|
+
|
|
28
|
+
No change to the API or the exported surface. Released with the Python
|
|
29
|
+
client, whose PyPI page is now its own README rather than a shorter copy.
|
|
30
|
+
|
|
31
|
+
## 1.14.1 — the README leads with the job
|
|
32
|
+
|
|
33
|
+
No change to the API or the exported surface. The README opens with
|
|
34
|
+
creating an address, sending, waiting for the answer and replying with
|
|
35
|
+
`messagesReply`, and the package's description and keywords say what it is
|
|
36
|
+
for: email inboxes for AI agents.
|
|
11
37
|
|
|
12
38
|
## 1.14.0 — clean bodies in a conversation
|
|
13
39
|
|
package/README.md
CHANGED
|
@@ -1,17 +1,74 @@
|
|
|
1
1
|
# @pidgeon-ai/sdk
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
webhook verifier.
|
|
6
|
-
|
|
7
|
-
**Zero dependencies.** Needs `fetch` and `crypto.subtle`, so it runs on
|
|
8
|
-
Node 18+, Bun, Deno, Cloudflare Workers and Vercel functions. ESM and
|
|
9
|
-
CommonJS.
|
|
3
|
+
Pidgeon is the email inbox API for AI agents. It gives agents their own inboxes
|
|
4
|
+
so they can work with emails just like a human. This is its TypeScript client:
|
|
5
|
+
one typed function per operation, plus a webhook verifier.
|
|
10
6
|
|
|
11
7
|
```bash
|
|
12
|
-
|
|
8
|
+
npm install @pidgeon-ai/sdk
|
|
13
9
|
```
|
|
14
10
|
|
|
11
|
+
Or `pnpm add @pidgeon-ai/sdk`. **Zero dependencies.** Needs `fetch` and
|
|
12
|
+
`crypto.subtle`, so it runs on Node 18+, Bun, Deno, Cloudflare Workers and
|
|
13
|
+
Vercel functions. ESM and CommonJS.
|
|
14
|
+
|
|
15
|
+
## Create an address, send, receive, reply
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import {
|
|
19
|
+
client,
|
|
20
|
+
identitiesCreate,
|
|
21
|
+
messagesAwait,
|
|
22
|
+
messagesReply,
|
|
23
|
+
messagesSend,
|
|
24
|
+
} from '@pidgeon-ai/sdk';
|
|
25
|
+
|
|
26
|
+
client.setConfig({ auth: () => process.env.PIDGEON_API_KEY! });
|
|
27
|
+
|
|
28
|
+
// 1. An address of its own. Any free name on pidgeon.email works with no DNS.
|
|
29
|
+
const { data: address } = await identitiesCreate({
|
|
30
|
+
body: { address: 'scout@pidgeon.email', type: 'agent' },
|
|
31
|
+
throwOnError: true,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// 2. Send from it.
|
|
35
|
+
await messagesSend({
|
|
36
|
+
body: {
|
|
37
|
+
from: address.data.email,
|
|
38
|
+
to: 'ops@example.com',
|
|
39
|
+
subject: 'Staging access',
|
|
40
|
+
text: 'Could you send me the access code?',
|
|
41
|
+
},
|
|
42
|
+
throwOnError: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// 3. Receive: one held-open request until the answer arrives, up to 60 seconds.
|
|
46
|
+
const { data: awaited } = await messagesAwait({
|
|
47
|
+
query: { identity_id: address.data.id, timeout: 60 },
|
|
48
|
+
throwOnError: true,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// 4. Reply into the same conversation. Recipients and subject come off the original.
|
|
52
|
+
if (awaited.data.message) {
|
|
53
|
+
console.log(awaited.data.message.extracted.codes);
|
|
54
|
+
await messagesReply({
|
|
55
|
+
path: { id: awaited.data.message.id },
|
|
56
|
+
body: { text: 'Thanks, that worked.' },
|
|
57
|
+
throwOnError: true,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`PIDGEON_API_KEY` is a `pgn_live_…` key. Make one at
|
|
63
|
+
[pidgeon.ai/app/developers/keys](https://pidgeon.ai/app/developers/keys), or
|
|
64
|
+
let your agent sign itself up: [pidgeon.ai/skill.md](https://pidgeon.ai/skill.md)
|
|
65
|
+
is two calls, and the only thing it needs from a person is a six-digit code.
|
|
66
|
+
|
|
67
|
+
In production, take a [signed webhook](#receiving-mail) rather than holding a
|
|
68
|
+
request open. Documentation: [pidgeon.ai/docs](https://pidgeon.ai/docs) ·
|
|
69
|
+
[API reference](https://pidgeon.ai/docs/reference) ·
|
|
70
|
+
[OpenAPI](https://pidgeon.ai/openapi.json).
|
|
71
|
+
|
|
15
72
|
## The shape
|
|
16
73
|
|
|
17
74
|
**There is no `Pidgeon` class.** Every operation is a function named for its
|
|
@@ -38,7 +95,7 @@ Mail arriving at an address your code owns becomes an event, and your
|
|
|
38
95
|
endpoint is called with a signed payload.
|
|
39
96
|
|
|
40
97
|
```ts
|
|
41
|
-
import { client, messagesGet,
|
|
98
|
+
import { client, messagesGet, messagesReply, verifyWebhook } from '@pidgeon-ai/sdk';
|
|
42
99
|
|
|
43
100
|
client.setConfig({ auth: () => process.env.PIDGEON_API_KEY! });
|
|
44
101
|
|
|
@@ -59,15 +116,10 @@ export async function POST(request: Request) {
|
|
|
59
116
|
throwOnError: true,
|
|
60
117
|
});
|
|
61
118
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
subject: `Re: ${mail.data.subject}`,
|
|
67
|
-
text: 'Got it — someone will be in touch.',
|
|
68
|
-
// Keeps the conversation together in the recipient's client too.
|
|
69
|
-
in_reply_to: mail.data.id,
|
|
70
|
-
},
|
|
119
|
+
// Into the same conversation, threaded in the recipient's client too.
|
|
120
|
+
await messagesReply({
|
|
121
|
+
path: { id: mail.data.id },
|
|
122
|
+
body: { text: 'Got it — someone will be in touch.' },
|
|
71
123
|
throwOnError: true,
|
|
72
124
|
});
|
|
73
125
|
|
|
@@ -174,4 +226,13 @@ Versioned independently of the API. The API is `/v1`; this package is
|
|
|
174
226
|
`1.x`, and semver applies to its own surface — the exported types, the
|
|
175
227
|
method signatures, the error shape. See `CHANGELOG.md`.
|
|
176
228
|
|
|
177
|
-
|
|
229
|
+
## Contributing
|
|
230
|
+
|
|
231
|
+
This package is generated from [`openapi.json`](https://pidgeon.ai/openapi.json),
|
|
232
|
+
the contract the API validates against, and published from
|
|
233
|
+
[pidgeon-ai/pidgeon-js](https://github.com/pidgeon-ai/pidgeon-js). A pull
|
|
234
|
+
request against generated code cannot be merged as written — the fix belongs
|
|
235
|
+
in the schema. [Open an issue](https://github.com/pidgeon-ai/pidgeon-js/issues)
|
|
236
|
+
and say what is wrong, or email [support@pidgeon.ai](mailto:support@pidgeon.ai).
|
|
237
|
+
|
|
238
|
+
MIT licensed.
|
package/dist/index.cjs
CHANGED
|
@@ -29,6 +29,7 @@ __export(index_exports, {
|
|
|
29
29
|
appPasswordsList: () => appPasswordsList,
|
|
30
30
|
appPasswordsRevoke: () => appPasswordsRevoke,
|
|
31
31
|
attachmentsDownloadUrl: () => attachmentsDownloadUrl,
|
|
32
|
+
attachmentsText: () => attachmentsText,
|
|
32
33
|
attachmentsUpload: () => attachmentsUpload,
|
|
33
34
|
calendarCreateEvent: () => calendarCreateEvent,
|
|
34
35
|
calendarDeleteEvent: () => calendarDeleteEvent,
|
|
@@ -1647,6 +1648,11 @@ var attachmentsDownloadUrl = (options) => (options.client ?? client).get({
|
|
|
1647
1648
|
url: "/attachments/{id}",
|
|
1648
1649
|
...options
|
|
1649
1650
|
});
|
|
1651
|
+
var attachmentsText = (options) => (options.client ?? client).get({
|
|
1652
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
1653
|
+
url: "/attachments/{id}/text",
|
|
1654
|
+
...options
|
|
1655
|
+
});
|
|
1650
1656
|
|
|
1651
1657
|
// src/webhooks.ts
|
|
1652
1658
|
var SIGNATURE_HEADER = "x-pidgeon-signature";
|
|
@@ -1808,6 +1814,7 @@ function sleep(ms, signal) {
|
|
|
1808
1814
|
appPasswordsList,
|
|
1809
1815
|
appPasswordsRevoke,
|
|
1810
1816
|
attachmentsDownloadUrl,
|
|
1817
|
+
attachmentsText,
|
|
1811
1818
|
attachmentsUpload,
|
|
1812
1819
|
calendarCreateEvent,
|
|
1813
1820
|
calendarDeleteEvent,
|