@curviate/sdk 0.37.0 → 0.38.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,106 @@ Versioning: semantic. Minor for additive changes, patch for bug fixes; no stabil
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.38.0] - 2026-09-26
13
+
14
+ Fixture and types regenerated against the deployed production document
15
+ (`https://api.curviate.com`, 130 paths, server
16
+ `f06ce7e52877ead27c1cfc62dde311c8cda9a325`). Adds programmatic connect at
17
+ scale: your own end-user id on accounts, tenant-wide account-status webhooks,
18
+ challenge selection on checkpoints, and seat purchase over the API.
19
+
20
+ ### Added
21
+
22
+ - **`accounts.addSeats({ qty })`, `accounts.cancelSeat(seatId)`,
23
+ `accounts.revertSeatCancellation(seatId)`.** Buy seats, schedule a seat's
24
+ end-of-period cancellation, and undo it, without the dashboard. Every
25
+ `addSeats` call buys the seats it asks for, so a repeated call buys again,
26
+ and the SDK never retries it. On `SUBSCRIPTION_BUSY` (503) the purchase could
27
+ not be confirmed: check the seat count with `accounts.listSeats()` before
28
+ trying again. A trialing workspace gets `TRIAL_ACTIVE_SEAT_LIMIT`.
29
+ Their types include the 402 refusals (no subscription, past due, dispute,
30
+ and on add a declined card) and the 503 `SUBSCRIPTION_BUSY`.
31
+ - **`external_id` on accounts.** Pass your own id for the account's end user on
32
+ `auth.intent` or `accounts.update` (`null` clears it). It is returned on
33
+ `accounts.get`/`list`, on the connect responses, and on every `account.*`
34
+ webhook payload (`AccountPayload.external_id`, `null` when unset).
35
+ `accounts.list({ external_id })` returns only that end user's accounts.
36
+ - **`metadata` is stored and read back.** `accounts.update({ metadata })` now
37
+ persists the map (at most 16 keys) and `accounts.get`/`list` return it;
38
+ `null` clears it.
39
+ - **`timezone` and `products` on `auth.intent`.** `timezone` is an IANA zone
40
+ name; `products` narrows the premium products asked for
41
+ (`["sales_navigator"]`, `["recruiter"]`, or `[]`).
42
+ - **Challenge selection.** A checkpoint can now be
43
+ `challenge_type: "challenge_selection"` with a `challenges` list
44
+ (`{ id, label, description }`). Answer it with
45
+ `auth.requestCheckpoint(accountId, { challenge: id })`, which returns the next
46
+ checkpoint.
47
+ - **Tenant-wide account-status webhooks.** `webhooks.create` with
48
+ `source: "account_status"` no longer needs `account_ids`: omit it to cover
49
+ every current and future account. `webhooks.update(id, { account_ids: null })`
50
+ switches an existing one.
51
+
52
+ ### Changed
53
+
54
+ - **`auth.requestCheckpoint` returns `200 | 202`.** Without a body it still
55
+ re-sends and returns `{ resent }`; with `{ challenge }` it returns the next
56
+ checkpoint. Code reading `result.resent` must narrow first
57
+ (`"status" in result` for the 202 checkpoint, `"resent" in result` for the
58
+ 200 re-send; each narrows only its true branch).
59
+ - **Webhook `account_ids` is `string[] | null` on reads.** `null` means a
60
+ tenant-wide `account_status` webhook.
61
+ - **Empty optional text is refused.** An empty `headline` on `users.update`,
62
+ an empty `subject` on `messaging.startChat` and an empty `message` on
63
+ `invites.send` are now rejected with `INVALID_REQUEST`. `bio: ""` is still
64
+ accepted (its type now reads `"" | string`).
65
+ - **`account.restricted` documented as "connected, some actions fail".** The
66
+ event also fires when one LinkedIn product on the account (Sales Navigator,
67
+ Recruiter) is failing, not only for a LinkedIn restriction. Surface it to a
68
+ human; a reconnect may restore a single failing product.
69
+
70
+ ## [0.37.1] - 2026-09-23
71
+
72
+ Fixture and types regenerated against the deployed production document
73
+ (`https://api.curviate.com`, 127 paths, server
74
+ `0b33680536a45681ed5ffe420006cb05c85fe683`). Description changes only; no type
75
+ shape changed.
76
+
77
+ ### Changed
78
+
79
+ - **Generated type descriptions follow the served document.** `is_sender` on
80
+ chat messages now documents that it is omitted when the connected account
81
+ cannot yet be identified (treat a missing value as unknown, not as received).
82
+ Recruiter search and project filters, and the job read's `sections`
83
+ parameter, are documented as trimmed before use rather than forwarded
84
+ verbatim.
85
+
86
+ ### Fixed
87
+
88
+ - **The retry decision now honours `retry_hint.kind: "never"`.** A retryable
89
+ code (`INTERNAL`, `PLATFORM_ERROR`, `PLATFORM_RATE_LIMIT`,
90
+ `RATE_LIMIT_ACCOUNT`, `RATE_LIMIT_TENANT`) whose envelope carries
91
+ `retry_hint: { kind: "never" }`, an explicit server instruction that this
92
+ exact refusal will not change on a retry (for example, an upstream response
93
+ in a shape this API cannot read), is no longer retried on GETs. Previously
94
+ the retry gate consulted only the code table, so a structural-drift 502
95
+ (`PLATFORM_ERROR` with `retry_likely_to_succeed: false` and
96
+ `retry_hint.kind: "never"`) was retried up to three times against an answer
97
+ that could not change.
98
+
99
+ `retry_likely_to_succeed` is still not consulted by the retry decision. The
100
+ server currently defaults it to `false` on several generic
101
+ "unresolved error" paths that are not a per-cause verdict, and honouring it
102
+ as written would have silently stopped retrying most undecoded server
103
+ errors. Filed back rather than shipped; unaffected callers see no
104
+ behaviour change.
105
+
106
+ - **An empty but present `Retry-After` header no longer reads as "retry in
107
+ 0ms".** `Number("")` is `0`, which is finite and non-negative, so it passed
108
+ the same check a real delay does; it now falls back to the same
109
+ conservative 30s the unparseable HTTP-date form already gets. Found in
110
+ passing while touching this file for the fix above; unrelated to it.
111
+
12
112
  ## [0.37.0] - 2026-09-22
13
113
 
14
114
  Fixture and types regenerated against the deployed production document