@pidgeon-ai/sdk 1.1.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 CHANGED
@@ -9,6 +9,91 @@ 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
+
82
+ ## 1.2.0 — the document says what its fields mean
83
+
84
+ **Additive, and a correction.**
85
+
86
+ **Added.** Every request field that means one thing everywhere now carries a
87
+ description, so the types say what `from`, `to`, `attachment_ids` and twenty
88
+ others are for — 0 of 136 had one before.
89
+
90
+ **Corrected.** `messagesSend` is typed `Sent` at `202`, which is what the API
91
+ has always answered. It was declared `Message` at `201`, a response that never
92
+ arrives — so a caller reading `data.subject` off a send got `undefined`, and
93
+ `send` and `reply` appeared to disagree about their shape when they never did.
94
+ Minor rather than major because nothing could have depended on a status code
95
+ the server does not send.
96
+
12
97
  ## 1.1.0 — the domain an address is on
13
98
 
14
99
  Additive. Nothing here changes a call that already works.
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.client ?? client).get({
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) => input.headers instanceof Headers ? input.headers.get(name) ?? void 0 : input.headers[name] ?? input.headers[name.toLowerCase()];
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,