@pidgeon-ai/sdk 1.2.0 → 1.3.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 +70 -0
- package/LICENSE +21 -0
- package/dist/index.cjs +25 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -12
- package/dist/index.d.ts +233 -12
- package/dist/index.js +23 -2
- package/dist/index.js.map +1 -1
- package/package.json +7 -3
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,76 @@ call shapes, the result shape — not to the API behind it.
|
|
|
9
9
|
|
|
10
10
|
## Unreleased
|
|
11
11
|
|
|
12
|
+
## 1.3.0 — a day of API that never reached a registry
|
|
13
|
+
|
|
14
|
+
**Additive, and one fix that was a blocker.**
|
|
15
|
+
|
|
16
|
+
1.2.0 went out on 14 October and then the contract moved for a day without
|
|
17
|
+
this number moving with it. A field test on 15 October installed the published
|
|
18
|
+
package, called a search the live API had been accepting since the morning,
|
|
19
|
+
and got a `TypeError` for an argument the contract no longer requires. It
|
|
20
|
+
built what it needed with a hand-written HTTP client instead. Everything below
|
|
21
|
+
had already shipped; none of it was installable.
|
|
22
|
+
|
|
23
|
+
**Fixed.** `verifyWebhook` reads the signature headers whatever case the
|
|
24
|
+
framework spells them in. The lookup was `headers[name] ?? headers[name
|
|
25
|
+
.toLowerCase()]` and `name` is already a lowercase constant — so it read the
|
|
26
|
+
same key twice, and a plain object keyed `X-Pidgeon-Signature` was rejected as
|
|
27
|
+
unsigned. Every existing test passed, because they all hand it a `Headers` or
|
|
28
|
+
a lowercase object and both are already normalised. The broken branch is
|
|
29
|
+
reached by an object somebody built themselves, which is what API Gateway
|
|
30
|
+
hands a Lambda. `pidgeon` on PyPI was always right about this.
|
|
31
|
+
|
|
32
|
+
**Added.**
|
|
33
|
+
|
|
34
|
+
- `meGet`. What a key is, what it may do, and how many addresses it reaches —
|
|
35
|
+
the first call a credential can make about itself.
|
|
36
|
+
- `eventsStream`'s endpoint is in the document. The client does not wrap SSE,
|
|
37
|
+
because a generated client has nowhere to put a long-lived connection; the
|
|
38
|
+
path, the cursor header and the event shape are typed so hand-rolling it is
|
|
39
|
+
twenty lines rather than a reverse-engineering exercise.
|
|
40
|
+
- `thread.created` is emitted and subscribable. It was declared, accepted by
|
|
41
|
+
`POST /webhooks`, and had never once fired.
|
|
42
|
+
- `from_self` on `message.received`. A workspace with several addresses sees
|
|
43
|
+
its own outbound mail arrive at the others, genuinely inbound, with nothing
|
|
44
|
+
to distinguish it from a stranger — so a handler written the obvious way
|
|
45
|
+
answers its own reply. Check it before you reply.
|
|
46
|
+
- Quota pacing on a refusal: `Retry-After` and `X-RateLimit-*-Day`, so a
|
|
47
|
+
client refused a send can compute when it may try again instead of guessing
|
|
48
|
+
a day.
|
|
49
|
+
|
|
50
|
+
**Declared, having always been returned.** Three fields the API sends and the
|
|
51
|
+
document did not mention, so the generated types dropped them and a caller had
|
|
52
|
+
to cast to reach them:
|
|
53
|
+
|
|
54
|
+
- `sync_cursor` on a folder listing. `GET /mailboxes/changes` documents
|
|
55
|
+
`since` as "the `sync_cursor` from a listing" and no listing declared one,
|
|
56
|
+
so the change feed was unreachable from a typed client without defeating
|
|
57
|
+
its own types.
|
|
58
|
+
- `folder` on a search hit, and `identity` beside `identity_id` — the address
|
|
59
|
+
rather than the uuid, which is what the rest of the API already carries on a
|
|
60
|
+
thread row, on an event and on `GET /messages/{id}`. A search is the one
|
|
61
|
+
endpoint that spans mailboxes, so it was the one that most needed to name
|
|
62
|
+
them and the only one that would not. A hit is now its own type,
|
|
63
|
+
`SearchHit`, rather than a `MessageListItem` with two fields missing.
|
|
64
|
+
- `colour` is the eight-value enum it has always been enforced as, not
|
|
65
|
+
`string`. The palette existed only in the refusal, so the first call
|
|
66
|
+
anybody writes fails — somebody who has written CSS passes a hex. The
|
|
67
|
+
refusal was already good and is kept word for word.
|
|
68
|
+
|
|
69
|
+
**Widened.** `messagesSearch` no longer requires `identity_id`. It searches
|
|
70
|
+
every address the credential reaches, which is what it has always done on the
|
|
71
|
+
server and what `skill.md` has always said; the document said "one mailbox at
|
|
72
|
+
a time" in prose while declaring the parameter optional, and the generator
|
|
73
|
+
followed the prose. `MessageListItem` carries `identity_id`, `to`,
|
|
74
|
+
`counterparty` and `counterparty_name`, so a hit can be attributed to a
|
|
75
|
+
mailbox without a second call.
|
|
76
|
+
|
|
77
|
+
**Also.** `identitiesCreate` on the shared domain, a 404 that stopped
|
|
78
|
+
pretending an address it had just listed did not exist, and `repository`
|
|
79
|
+
fields that resolve — all four packages pointed at a private repository that
|
|
80
|
+
404s for everybody who installs one.
|
|
81
|
+
|
|
12
82
|
## 1.2.0 — the document says what its fields mean
|
|
13
83
|
|
|
14
84
|
**Additive, and a correction.**
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 PCN Labs OÜ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
CHANGED
|
@@ -62,6 +62,7 @@ __export(index_exports, {
|
|
|
62
62
|
draftsUpdate: () => draftsUpdate,
|
|
63
63
|
eventsGet: () => eventsGet,
|
|
64
64
|
eventsList: () => eventsList,
|
|
65
|
+
eventsStream: () => eventsStream,
|
|
65
66
|
identitiesAccessCreate: () => identitiesAccessCreate,
|
|
66
67
|
identitiesAccessDelete: () => identitiesAccessDelete,
|
|
67
68
|
identitiesAccessGet: () => identitiesAccessGet,
|
|
@@ -90,6 +91,7 @@ __export(index_exports, {
|
|
|
90
91
|
mailboxesEmptyTrash: () => mailboxesEmptyTrash,
|
|
91
92
|
mailboxesList: () => mailboxesList,
|
|
92
93
|
mailboxesListFolder: () => mailboxesListFolder,
|
|
94
|
+
meGet: () => meGet,
|
|
93
95
|
messagesAct: () => messagesAct,
|
|
94
96
|
messagesForward: () => messagesForward,
|
|
95
97
|
messagesGet: () => messagesGet,
|
|
@@ -1117,7 +1119,7 @@ var messagesSend = (options) => (options.client ?? client).post({
|
|
|
1117
1119
|
...options.headers
|
|
1118
1120
|
}
|
|
1119
1121
|
});
|
|
1120
|
-
var messagesSearch = (options) => (options
|
|
1122
|
+
var messagesSearch = (options) => (options?.client ?? client).get({
|
|
1121
1123
|
security: [{ scheme: "bearer", type: "http" }],
|
|
1122
1124
|
url: "/messages/search",
|
|
1123
1125
|
...options
|
|
@@ -1353,6 +1355,11 @@ var appPasswordsRevoke = (options) => (options.client ?? client).delete({
|
|
|
1353
1355
|
url: "/app-passwords/{id}",
|
|
1354
1356
|
...options
|
|
1355
1357
|
});
|
|
1358
|
+
var meGet = (options) => (options?.client ?? client).get({
|
|
1359
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
1360
|
+
url: "/me",
|
|
1361
|
+
...options
|
|
1362
|
+
});
|
|
1356
1363
|
var workspaceGet = (options) => (options?.client ?? client).get({
|
|
1357
1364
|
security: [{ scheme: "bearer", type: "http" }],
|
|
1358
1365
|
url: "/workspace",
|
|
@@ -1368,6 +1375,11 @@ var eventsList = (options) => (options?.client ?? client).get({
|
|
|
1368
1375
|
url: "/events",
|
|
1369
1376
|
...options
|
|
1370
1377
|
});
|
|
1378
|
+
var eventsStream = (options) => (options?.client ?? client).sse.get({
|
|
1379
|
+
security: [{ scheme: "bearer", type: "http" }],
|
|
1380
|
+
url: "/events/stream",
|
|
1381
|
+
...options
|
|
1382
|
+
});
|
|
1371
1383
|
var eventsGet = (options) => (options.client ?? client).get({
|
|
1372
1384
|
security: [{ scheme: "bearer", type: "http" }],
|
|
1373
1385
|
url: "/events/{id}",
|
|
@@ -1589,7 +1601,16 @@ var attachmentsDownloadUrl = (options) => (options.client ?? client).get({
|
|
|
1589
1601
|
var SIGNATURE_HEADER = "x-pidgeon-signature";
|
|
1590
1602
|
var TIMESTAMP_HEADER = "x-pidgeon-timestamp";
|
|
1591
1603
|
async function verifyWebhook(input) {
|
|
1592
|
-
const get = (name) =>
|
|
1604
|
+
const get = (name) => {
|
|
1605
|
+
if (input.headers instanceof Headers) return input.headers.get(name) ?? void 0;
|
|
1606
|
+
const direct = input.headers[name];
|
|
1607
|
+
if (direct !== void 0) return direct;
|
|
1608
|
+
const wanted = name.toLowerCase();
|
|
1609
|
+
for (const [key2, value] of Object.entries(input.headers)) {
|
|
1610
|
+
if (key2.toLowerCase() === wanted) return value;
|
|
1611
|
+
}
|
|
1612
|
+
return void 0;
|
|
1613
|
+
};
|
|
1593
1614
|
const timestamp = get(TIMESTAMP_HEADER);
|
|
1594
1615
|
const signature = get(SIGNATURE_HEADER);
|
|
1595
1616
|
if (!timestamp || !signature) throw new Error("This request is not signed.");
|
|
@@ -1670,6 +1691,7 @@ function constantTimeEqual(a, b) {
|
|
|
1670
1691
|
draftsUpdate,
|
|
1671
1692
|
eventsGet,
|
|
1672
1693
|
eventsList,
|
|
1694
|
+
eventsStream,
|
|
1673
1695
|
identitiesAccessCreate,
|
|
1674
1696
|
identitiesAccessDelete,
|
|
1675
1697
|
identitiesAccessGet,
|
|
@@ -1698,6 +1720,7 @@ function constantTimeEqual(a, b) {
|
|
|
1698
1720
|
mailboxesEmptyTrash,
|
|
1699
1721
|
mailboxesList,
|
|
1700
1722
|
mailboxesListFolder,
|
|
1723
|
+
meGet,
|
|
1701
1724
|
messagesAct,
|
|
1702
1725
|
messagesForward,
|
|
1703
1726
|
messagesGet,
|