@curviate/sdk 0.29.0 → 0.30.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 +173 -8
- package/README.md +70 -0
- package/dist/index.d.ts +369 -145
- package/dist/index.js +278 -32
- package/package.json +1 -1
- package/src/generated/types.ts +112 -103
package/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,173 @@ Versioning: semantic. Minor for additive changes, patch for bug fixes; no stabil
|
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
+
## [0.30.0] - 2026-09-09
|
|
11
|
+
|
|
12
|
+
Fixture and types regenerated against the deployed staging document
|
|
13
|
+
(`https://api.staging.curviate.com`, 125 paths); the exact source commit is
|
|
14
|
+
recorded in `fixtures/PROVENANCE.json`.
|
|
15
|
+
|
|
16
|
+
Product tiers are retired. Curviate no longer sells a Sales Navigator or
|
|
17
|
+
Recruiter product, no seat carries a tier flag, and one ordinary paid seat now
|
|
18
|
+
entitles the entire API surface.
|
|
19
|
+
|
|
20
|
+
**What actually happens to the error-code union: 45 codes to 67. Twenty-three
|
|
21
|
+
added, one removed, and the two retired tier codes KEPT.**
|
|
22
|
+
|
|
23
|
+
- **Added (23).** `NO_ACTIVE_SEAT` and `BETA_NOT_ENABLED`, plus twenty-one codes
|
|
24
|
+
the API already returned that this SDK had been erasing to `INTERNAL`.
|
|
25
|
+
- **Removed (1).** `RATE_LIMITED`, which the API never produced at all.
|
|
26
|
+
- **Kept, deprecated (2).** `TIER_NOT_ACTIVE` and `PREMIUM_CONFLICT` are still
|
|
27
|
+
exported. They are *not* gone, and that is deliberate: a client talks to a
|
|
28
|
+
deployment rather than to a changelog, and an API that predates the
|
|
29
|
+
seat-based entitlement rollout still answers them. See **Deprecated** below
|
|
30
|
+
before you delete a `case`.
|
|
31
|
+
- **Removed field (1).** `CurviateError.requiredTier`, with `RequiredTier`,
|
|
32
|
+
`REQUIRED_TIERS` and `KNOWN_REQUIRED_TIERS`. This one really is gone, so a
|
|
33
|
+
pre-rollout deployment gives you the code without the field. See **Removed**.
|
|
34
|
+
|
|
35
|
+
**Breaking, and unusually so for a 0.x minor**, in two narrow places rather than
|
|
36
|
+
across the union: the `requiredTier` field is gone, and `RATE_LIMITED` is gone.
|
|
37
|
+
Everything else here is additive or a deprecation.
|
|
38
|
+
|
|
39
|
+
Ripple: this release follows the server-side gate collapse, the connect rework
|
|
40
|
+
and the beta consent gate, each already deployed. Nothing here is an SDK-only
|
|
41
|
+
decision; the wire contract moved first and this release catches the typed
|
|
42
|
+
client up to it, in one release rather than three.
|
|
43
|
+
|
|
44
|
+
### Deprecated
|
|
45
|
+
|
|
46
|
+
- **`TIER_NOT_ACTIVE` is replaced by `NO_ACTIVE_SEAT`, and `PREMIUM_CONFLICT`
|
|
47
|
+
is withdrawn with no replacement, but BOTH ARE STILL EXPORTED.**
|
|
48
|
+
|
|
49
|
+
Not a courtesy, and worth understanding before you delete a `case`: a client
|
|
50
|
+
talks to a DEPLOYMENT, not to a changelog. An API that has not taken the
|
|
51
|
+
seat-based entitlement rollout yet still answers `TIER_NOT_ACTIVE`, and a
|
|
52
|
+
union that had dropped the code would decode it to `INTERNAL` there, turning
|
|
53
|
+
a fixable billing refusal into what looks like a server fault, on exactly the
|
|
54
|
+
deployments most likely to send it. Carrying a dead code for one release is
|
|
55
|
+
the cheaper mistake.
|
|
56
|
+
|
|
57
|
+
So handle both for now: `NO_ACTIVE_SEAT` from a current deployment,
|
|
58
|
+
`TIER_NOT_ACTIVE` from an older one. They mean the same thing to a caller,
|
|
59
|
+
and both are `user_fixable` 403s whose remedy is a seat. Each is marked
|
|
60
|
+
`@deprecated` in its JSDoc with the replacement named, so your editor says so
|
|
61
|
+
at the call site.
|
|
62
|
+
|
|
63
|
+
They are removed in the first release after every deployment carries the new
|
|
64
|
+
contract. That removal will be breaking and will say so.
|
|
65
|
+
|
|
66
|
+
`CurviateError.requiredTier` is NOT kept, however: see Removed below. On a
|
|
67
|
+
pre-rollout deployment you get the code without the field, which is enough to
|
|
68
|
+
route on, since the message names the tier.
|
|
69
|
+
|
|
70
|
+
### Removed
|
|
71
|
+
|
|
72
|
+
- **`RATE_LIMITED` is gone: the API never produced it.** The substrate's own
|
|
73
|
+
`RATE_LIMITED` is translated to `PLATFORM_RATE_LIMIT` (429) before any
|
|
74
|
+
response is written, so no caller could ever receive the code this SDK was
|
|
75
|
+
exporting. A `case "RATE_LIMITED"` was dead code, and worse than dead: it
|
|
76
|
+
read as the handled branch for a throttle that actually arrives as
|
|
77
|
+
`PLATFORM_RATE_LIMIT`, so the real one fell through to `default`.
|
|
78
|
+
|
|
79
|
+
The codes to branch on for throttling are `RATE_LIMIT_ACCOUNT`,
|
|
80
|
+
`RATE_LIMIT_TENANT`, `PLATFORM_RATE_LIMIT` and `LINKEDIN_RATE_LIMITED`. If
|
|
81
|
+
you matched `RATE_LIMITED`, delete the arm; nothing was reaching it.
|
|
82
|
+
|
|
83
|
+
- **`CurviateError.requiredTier` is gone**, along with the `RequiredTier` type,
|
|
84
|
+
the `REQUIRED_TIERS` array and the `KNOWN_REQUIRED_TIERS` set. There is no
|
|
85
|
+
tier to name on a refusal any more, so the field carried nothing. It is also
|
|
86
|
+
gone from `CurviateError.toJSON()`, so a serialized error no longer has the
|
|
87
|
+
key at all. Code reading `err.requiredTier` to route an upgrade should read
|
|
88
|
+
`err.code` instead and route on the three refusals described in the README.
|
|
89
|
+
|
|
90
|
+
### Added
|
|
91
|
+
|
|
92
|
+
- **Twenty-one codes previously collapsed to `INTERNAL` now surface.** Each is
|
|
93
|
+
returned by a `/v1` route, the `/v1` catch-all, or a shared handler one of
|
|
94
|
+
them calls, so each already reached this SDK's decoder, and because the
|
|
95
|
+
exported union did not carry them, the decoder erased every one to
|
|
96
|
+
`INTERNAL`. A refusal the caller could usually fix arrived looking like a
|
|
97
|
+
server fault, with no `switch` arm possible.
|
|
98
|
+
|
|
99
|
+
Routing and reads: `NOT_FOUND`, `REACTION_NOT_FOUND`. Upstream failures on
|
|
100
|
+
connect and billing: `SUBSTRATE_LINK_FAILED`, `SUBSTRATE_CAP_REACHED`,
|
|
101
|
+
`BILLING_CHECKOUT_FAILED`, `BILLING_PORTAL_UNAVAILABLE`. Tenant standing:
|
|
102
|
+
`ACCOUNT_DISPUTED`, `ACCOUNT_LINKING_DISABLED`, `PERIOD_LOCKED`. Seat and
|
|
103
|
+
subscription conflicts: `SEAT_NOT_EMPTY`, `SEAT_PROVISIONAL`,
|
|
104
|
+
`SUBSCRIPTION_ALREADY_EXISTS`, `ALREADY_CANCELLED`,
|
|
105
|
+
`CANCELLATION_ALREADY_EFFECTIVE`, `INVALID_CANCELLATION_SOURCE`. Free trial:
|
|
106
|
+
`TRIAL_EXPIRED`, `TRIAL_SEAT_LIMIT`, `TRIAL_ACTIVE_SEAT_LIMIT`,
|
|
107
|
+
`TRIAL_IDENTITY_ALREADY_USED`, `TRIAL_IDENTITY_UNRESOLVED`. Admin tenants:
|
|
108
|
+
`ADMIN_BYPASS`.
|
|
109
|
+
|
|
110
|
+
Additive for anyone who was already handling `INTERNAL` as their fallback:
|
|
111
|
+
those cases now arrive with their real code instead, so a `default` arm that
|
|
112
|
+
retried on `retryLikelyToSucceed` keeps working and can be narrowed. If you
|
|
113
|
+
match on `INTERNAL` specifically to detect one of these, that check needs
|
|
114
|
+
updating.
|
|
115
|
+
|
|
116
|
+
`ADMIN_BYPASS` is a correction as much as an addition: this file previously
|
|
117
|
+
named it as an example of a code that never reaches a caller, while the
|
|
118
|
+
server constructed it at nine sites inside its versioned billing endpoints.
|
|
119
|
+
|
|
120
|
+
- **`BETA_NOT_ENABLED` (403).** A beta-gated operation refuses this until a
|
|
121
|
+
human enables beta operations for the workspace in Settings, or the request
|
|
122
|
+
carries the `X-Curviate-Beta` header. It is the third of three independent
|
|
123
|
+
403 entitlement refusals, and nothing about it involves the seat or the
|
|
124
|
+
LinkedIn subscription.
|
|
125
|
+
|
|
126
|
+
- **`@beta` JSDoc markers on every operation the served document badges beta**,
|
|
127
|
+
which today is the whole Sales Navigator, Recruiter and inbox surface plus the
|
|
128
|
+
two company-inbox reads. Your editor now says so before you call one. The
|
|
129
|
+
badge is a superset of the gate: a badged operation is not necessarily gated,
|
|
130
|
+
so read the code on a refusal rather than inferring it from the badge. The
|
|
131
|
+
markers are derived from the served badge and checked in both directions, so
|
|
132
|
+
they cannot silently drift from it.
|
|
133
|
+
|
|
134
|
+
- **README: "Three refusals, three codes"**, a table separating
|
|
135
|
+
`NO_ACTIVE_SEAT` (fix it in Curviate billing) from
|
|
136
|
+
`LINKEDIN_FEATURE_NOT_SUBSCRIBED` (fix it on LinkedIn) from
|
|
137
|
+
`BETA_NOT_ENABLED` (a human opts the workspace in), because all three are 403
|
|
138
|
+
and all three read alike in prose. It also states that request validation runs
|
|
139
|
+
before every entitlement check, so an `INVALID_REQUEST` says nothing about
|
|
140
|
+
entitlement, and a 403 from one of the three proves the request itself
|
|
141
|
+
validated cleanly.
|
|
142
|
+
|
|
143
|
+
- **README: "Beta operations"**, on what the badge means and how it differs from
|
|
144
|
+
the gate.
|
|
145
|
+
|
|
146
|
+
### Changed
|
|
147
|
+
|
|
148
|
+
- **Sales Navigator and Recruiter JSDoc no longer describes a Curviate-side
|
|
149
|
+
entitlement.** Neither namespace has a product to buy and neither carries a
|
|
150
|
+
tier: one ordinary paid seat entitles every method. What they do need is the
|
|
151
|
+
LinkedIn account's own subscription, and an account whose LinkedIn lacks it
|
|
152
|
+
refuses `LINKEDIN_FEATURE_NOT_SUBSCRIBED` with a remedy on LinkedIn rather
|
|
153
|
+
than in Curviate billing. The namespace headers now say that instead of naming
|
|
154
|
+
a tier.
|
|
155
|
+
|
|
156
|
+
- **`auth.intent()` connect scope is no longer seat-derived.** The connect asks
|
|
157
|
+
for every product (classic, company, sales_navigator, recruiter) and LinkedIn
|
|
158
|
+
activates whichever ones the account actually holds; `requested_products` on
|
|
159
|
+
the account reports what was ASKED for, not what is attached. The optional
|
|
160
|
+
`linkedin_premium` (`"sales_navigator"` | `"recruiter"`) narrows one
|
|
161
|
+
connection, and **is never remembered**: a later connect or reconnect that
|
|
162
|
+
omits it widens the scope back to every product, so it has to be restated on
|
|
163
|
+
every call where Recruiter must win. `trial_premium` is gone from the connect
|
|
164
|
+
surface.
|
|
165
|
+
|
|
166
|
+
- **The taxonomy is no longer documented as additive-only.** It tracks the
|
|
167
|
+
served document: a code the API stops returning is removed and a renamed code
|
|
168
|
+
is renamed, because a dead code in the union is worse than a breaking change
|
|
169
|
+
a caller can see. Such changes are called out here, as this entry does.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
10
173
|
## [0.29.0] - 2026-09-07
|
|
11
174
|
|
|
12
175
|
Fixture and types regenerated against the deployed staging document
|
|
13
|
-
(`https://api.staging.curviate.com`,
|
|
176
|
+
(`https://api.staging.curviate.com`, 125 paths; source commit in `fixtures/PROVENANCE.json`).
|
|
14
177
|
Additive only: `safety-policy` now says where `limit_profile` came from, and an
|
|
15
178
|
operator override can be released without a reconnect.
|
|
16
179
|
|
|
@@ -55,7 +218,7 @@ operator override can be released without a reconnect.
|
|
|
55
218
|
## [0.28.0] - 2026-09-07
|
|
56
219
|
|
|
57
220
|
Fixture regenerated against the deployed staging document
|
|
58
|
-
(`https://api.staging.curviate.com`,
|
|
221
|
+
(`https://api.staging.curviate.com`, 125 paths; source commit in `fixtures/PROVENANCE.json`).
|
|
59
222
|
**BREAKING**: `messaging.searchChats` now rejects a `query` shorter than 3
|
|
60
223
|
characters server-side. Pre-1.0 a breaking change ships as a minor, so a caret
|
|
61
224
|
range on `0.27.x` will not pick this up.
|
|
@@ -97,7 +260,7 @@ range on `0.27.x` will not pick this up.
|
|
|
97
260
|
## [0.27.0] - 2026-09-06
|
|
98
261
|
|
|
99
262
|
Fixture regenerated against the deployed production document
|
|
100
|
-
(`https://api.curviate.com`,
|
|
263
|
+
(`https://api.curviate.com`, 125 paths; source commit in `fixtures/PROVENANCE.json`).
|
|
101
264
|
**BREAKING**: the `message.delivered` webhook event is gone from the catalogue,
|
|
102
265
|
from `CurviateEvent`, and from the events a subscription can be created with.
|
|
103
266
|
Everything else here is additive or description-only. Pre-1.0 a breaking change
|
|
@@ -166,7 +329,7 @@ ships as a minor, so a caret range on `0.26.x` will not pick this up.
|
|
|
166
329
|
## [0.26.0] - 2026-09-06
|
|
167
330
|
|
|
168
331
|
Fixture regenerated against the deployed production document
|
|
169
|
-
(`https://api.curviate.com`,
|
|
332
|
+
(`https://api.curviate.com`, 125 paths; source commit in `fixtures/PROVENANCE.json`).
|
|
170
333
|
**BREAKING at the type level** for a consumer that reads `row` off an error
|
|
171
334
|
or a safety warning as a `string`: it is now `string | null` on both. Three
|
|
172
335
|
response enums also widen, which reds an exhaustive `switch` with a `never`
|
|
@@ -559,7 +722,8 @@ version bump. A `0.21.0` would have reached nobody, because a caret on a `0.x`
|
|
|
559
722
|
version never resolves the next minor.
|
|
560
723
|
|
|
561
724
|
The generated types are a mirror of the served OpenAPI document. This release
|
|
562
|
-
is a regeneration against that document at
|
|
725
|
+
is a regeneration against that document, at the commit recorded in
|
|
726
|
+
`fixtures/PROVENANCE.json`; nothing
|
|
563
727
|
was hand-edited.
|
|
564
728
|
|
|
565
729
|
### Fixed
|
|
@@ -664,9 +828,10 @@ on the next install with no consumer-side version bump.
|
|
|
664
828
|
|
|
665
829
|
Generated types are rebuilt from the **served** OpenAPI document rather than a
|
|
666
830
|
hand-refreshed snapshot, and the snapshot itself now records where it came from.
|
|
667
|
-
Source of this release: `https://api.staging.curviate.com
|
|
668
|
-
|
|
669
|
-
|
|
831
|
+
Source of this release: `https://api.staging.curviate.com`. The exact source
|
|
832
|
+
commit is recorded in `fixtures/PROVENANCE.json` rather than here, because this
|
|
833
|
+
file ships inside the published package and an API commit id is not something a
|
|
834
|
+
consumer of it can resolve.
|
|
670
835
|
|
|
671
836
|
### Changed
|
|
672
837
|
|
package/README.md
CHANGED
|
@@ -144,6 +144,76 @@ exported `ErrorCode` type is the complete set, so `tsc` tells you when a `switch
|
|
|
144
144
|
|
|
145
145
|
---
|
|
146
146
|
|
|
147
|
+
## Three refusals, three codes
|
|
148
|
+
|
|
149
|
+
A `403` from this API is one of three completely separate refusals. They read alike
|
|
150
|
+
in prose and they are fixed in three different places, so branch on `err.code` and
|
|
151
|
+
never on the message.
|
|
152
|
+
|
|
153
|
+
| Code | What is missing | Who fixes it, and where |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| `NO_ACTIVE_SEAT` | Your Curviate workspace has no active paid seat covering the account. | You, in Curviate billing. Buy or attach a seat, then retry. |
|
|
156
|
+
| `LINKEDIN_FEATURE_NOT_SUBSCRIBED` | The LinkedIn account itself lacks the LinkedIn subscription the operation needs, such as Sales Navigator or Recruiter. | The account owner, on LinkedIn. No amount of Curviate billing lifts this one. |
|
|
157
|
+
| `BETA_NOT_ENABLED` | The operation is beta-gated and your workspace has not opted into beta operations. | A human, in Settings ("Allow beta operations"), or per request with the `X-Curviate-Beta` header. |
|
|
158
|
+
|
|
159
|
+
**There is no product tier.** One ordinary paid seat entitles the whole API surface,
|
|
160
|
+
Sales Navigator and Recruiter included. Nothing on a seat names a product, no refusal
|
|
161
|
+
asks you to upgrade a plan, and there is no field on the error saying which tier to
|
|
162
|
+
buy, because there are no tiers to buy. What a premium namespace still needs is the
|
|
163
|
+
LinkedIn account's own subscription, which is the second row above.
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
try {
|
|
167
|
+
await acc.salesNavigator.searchPeople({ keywords: "cto" });
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (!isCurviateError(err)) throw err;
|
|
170
|
+
switch (err.code) {
|
|
171
|
+
case "NO_ACTIVE_SEAT":
|
|
172
|
+
// Curviate-side. Attach a seat in Billing.
|
|
173
|
+
break;
|
|
174
|
+
case "LINKEDIN_FEATURE_NOT_SUBSCRIBED":
|
|
175
|
+
// LinkedIn-side. The account needs its own Sales Navigator subscription.
|
|
176
|
+
break;
|
|
177
|
+
case "BETA_NOT_ENABLED":
|
|
178
|
+
// Consent-side. A human enables beta in Settings for this workspace.
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Request validation runs before every entitlement check, so `INVALID_REQUEST` tells
|
|
185
|
+
you nothing about entitlement.** A malformed body is rejected with `400
|
|
186
|
+
INVALID_REQUEST` while the seat, the LinkedIn subscription and beta consent are all
|
|
187
|
+
still unexamined. A caller that reads a `400` as "my request was fine, my entitlement
|
|
188
|
+
is not" has it backwards: fix the request, send it again, and only then does a `403`
|
|
189
|
+
mean anything about what you are entitled to. The reverse holds too, and is the more
|
|
190
|
+
useful half: a `403` from one of the three codes above proves the request itself
|
|
191
|
+
parsed and validated cleanly.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Beta operations
|
|
196
|
+
|
|
197
|
+
Some operations are marked beta, because they have not been exercised against a real
|
|
198
|
+
LinkedIn subscription yet and their response shapes may still move. Every beta method
|
|
199
|
+
in this SDK carries an `@beta` tag in its JSDoc, so your editor tells you before you
|
|
200
|
+
call it; whole namespaces that are beta say so on the namespace as well.
|
|
201
|
+
|
|
202
|
+
The Sales Navigator, Recruiter and `inboxes` surfaces are beta in full today. Beta is
|
|
203
|
+
per operation, not per namespace, so a mostly-stable namespace can carry a beta method:
|
|
204
|
+
`companies.chats()` and `companies.searchChats()` are beta while the rest of
|
|
205
|
+
`companies` is not. Read the tag on the method you are calling rather than inferring it
|
|
206
|
+
from its neighbours.
|
|
207
|
+
|
|
208
|
+
The badge is a superset of the gate: an operation can be badged beta and still be
|
|
209
|
+
callable by anyone. A beta-GATED operation is the narrower set that actually refuses
|
|
210
|
+
`BETA_NOT_ENABLED` until a human enables beta operations for the workspace in
|
|
211
|
+
Settings, or the individual request carries `X-Curviate-Beta: true`. Because the two
|
|
212
|
+
move independently, read the code on a refusal rather than inferring the gate from
|
|
213
|
+
the badge.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
147
217
|
## Retrieval modes
|
|
148
218
|
|
|
149
219
|
Some reads can be answered from Curviate's own store instead of a live LinkedIn
|