@bisibility/sdk 0.6.0 → 0.7.1

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
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.7.1 - 2026-08-02
6
+
7
+ - Republished the 0.7.0 API surface after correcting release validation; runtime behavior is unchanged.
8
+
9
+ ## 0.7.0 - 2026-08-02
10
+
11
+ - **Breaking for typed consumers:** `getHealth()`, `getLiveness()`, and `getReadiness()` now return
12
+ status-only responses; degraded health and readiness HTTP 503 responses return normally without
13
+ retries, while other endpoints retain 503 retries.
14
+ - Added resource-oriented namespaces such as `client.keywords.*`, `client.team.*`, and
15
+ `client.imports.*`; flat methods remain available as deprecated delegates until 1.0.
16
+ - Added typed Saved Keywords list, iterator, create, and delete operations with `svkw` public IDs.
17
+ - Added `Bisibility-API-Version` compatibility declarations, lazy server compatibility checks,
18
+ and `BisibilityApiVersionError` for unsupported newer server contracts.
19
+
20
+ ## 0.6.1 - 2026-07-30
21
+
22
+ - Improved package metadata to describe the SDK's SEO rank-tracking, keyword, and ranking-history
23
+ capabilities.
24
+
3
25
  ## 0.6.0 - 2026-07-29
4
26
 
5
27
  - Breaking for API consumers: adopt the public ID v3 prefix registry and reject identifiers that
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
  > [API reference](https://bisibility.com/docs/api/overview) ·
9
9
  > [Roadmap](https://bisibility.com/roadmap)
10
10
  >
11
- > **Status:** Published on npm as v0.4.0.
11
+ > **Status:** Published on npm as v0.6.1.
12
12
 
13
13
  TypeScript SDK for the Bisibility REST API.
14
14
 
@@ -35,11 +35,11 @@ const bisibility = new BisibilityClient({
35
35
  apiKey: process.env.BISIBILITY_API_KEY
36
36
  });
37
37
 
38
- const projects = await bisibility.listProjects();
38
+ const projects = await bisibility.projects.list();
39
39
  const projectId = projects.data[0]?.id;
40
40
 
41
41
  if (projectId) {
42
- const created = await bisibility.addKeywords(projectId, {
42
+ const created = await bisibility.keywords.add(projectId, {
43
43
  keywords: [
44
44
  {
45
45
  keyword: "rank tracker api",
@@ -51,7 +51,7 @@ if (projectId) {
51
51
 
52
52
  const keywordId = created.results[0]?.keyword.id;
53
53
  if (keywordId) {
54
- const check = await bisibility.runRankCheck(keywordId);
54
+ const check = await bisibility.rankChecks.run(keywordId);
55
55
  console.log(check.position, check.ranking_url);
56
56
  }
57
57
  }
@@ -80,9 +80,9 @@ const bisibility = new BisibilityClient({
80
80
  projectId: process.env.BISIBILITY_PROJECT_ID
81
81
  });
82
82
 
83
- const me = await bisibility.getMe();
84
- const project = await bisibility.createProject({ domain: "example.com", name: "Example" });
85
- await bisibility.createProjectApiKey(project.id, { name: "CI" });
83
+ const me = await bisibility.account.get();
84
+ const project = await bisibility.projects.create({ domain: "example.com", name: "Example" });
85
+ await bisibility.apiKeys.create({ name: "CI" }, { projectId: project.id });
86
86
  ```
87
87
 
88
88
  A custom `fetch` implementation can be injected for older runtimes, proxies, or testing:
@@ -112,7 +112,7 @@ up to 60 seconds.
112
112
  Every method accepts per-request options:
113
113
 
114
114
  ```ts
115
- await bisibility.listProjects({
115
+ await bisibility.projects.list({
116
116
  headers: { "X-Request-Id": "..." },
117
117
  signal: controller.signal, // your own AbortSignal
118
118
  timeout: 10_000 // ms; composed with `signal` when both are set
@@ -122,6 +122,15 @@ await bisibility.listProjects({
122
122
  Without an explicit timeout or signal, every attempt has a 30-second timeout. Set `timeout: null`
123
123
  on the client or an individual request to opt out.
124
124
 
125
+ ### API version compatibility
126
+
127
+ The SDK declares `Bisibility-API-Version: v1` on every request. Before its first ordinary API
128
+ operation, each client lazily checks `/capabilities` once; calling `getCapabilities()` first
129
+ satisfies the same check without a duplicate request. A server that advertises `apiVersions` but
130
+ does not serve `v1` fails with `BisibilityApiVersionError` before the requested operation runs.
131
+ Older servers whose capabilities response has no `apiVersions` field remain compatible, and the
132
+ original request continues normally.
133
+
125
134
  ## Public resource IDs
126
135
 
127
136
  Every resource identifier accepted or returned by the SDK uses public ID v3. The
@@ -139,38 +148,38 @@ Locations are identified by `location_key`; they do not expose a location ID.
139
148
  Cloud import and export payloads use schema version 5 only. Pagination cursors are opaque SDK
140
149
  values; v3 API cursors returned by the server must be passed back unchanged.
141
150
 
142
- ## Methods
143
-
144
- - Discovery: `getHealth`, `getOpenApi`, `getCapabilities`, `getLlmsText`, `searchLocations`
145
- - Public cost (no API key required): `getProviderRates`, `getCostEstimate`
146
- - Account and personal tokens: `getMe`, `updateMe`, `listMyTokens`, `createMyToken`,
147
- `revokeMyToken`
148
- - Projects: `listProjects`, `createProject`, `getProject`, `updateProject`, `deleteProject`,
149
- `updateProjectDefaults`
150
- - API keys: `listApiKeys`, `createApiKey`, `revokeApiKey`, `listProjectApiKeys`,
151
- `createProjectApiKey`
152
- - Webhooks: `listWebhooks`, `createWebhook`, `updateWebhook`, `deleteWebhook`
153
- - Keywords: `listKeywords`, `iterateKeywords`, `addKeywords`, `getKeyword`, `updateKeyword`,
154
- `setKeywordTargetUrl`, `deleteKeyword`, `bulkUpdateKeywords`, `listRankedKeywordSuggestions`,
155
- `researchKeywords`, `getKeywordMetrics`
156
- - Backlinks: `analyzeBacklinks`, `loadMoreBacklinkRows`
157
- - Rank checks: `listRankChecks`, `runRankCheck`, `getRankCheckResult`, `exportRankHistory`,
158
- `iterateRankHistoryExport`
159
- - Sitemap monitors: `listSitemapMonitors`, `updateSitemapMonitor`
160
- - Signals: `createSignal`, `listSignals`
161
- - Alert rules and triggered alerts: `listAlertRules`, `createAlertRule`, `updateAlertRule`,
162
- `deleteAlertRule`, `listTriggeredAlerts`, `muteTriggeredAlert`, `markProjectAlertsRead`
163
- - Team: `listTeamMembers`, `listTeamInvites`, `createTeamInvite`, `revokeTeamInvite`,
164
- `revokeTeamInviteById`, `updateTeamMemberRole`, `removeTeamMember`, `resendTeamInvite`
165
- - Analytics: `listTrafficSnapshots`, `listSearchPerformanceQueryStats`, `syncProjectTraffic`
166
- - Providers: `listProviders`, `connectProvider`, `testProviderConnection`,
167
- `updateProviderSettings`, `setProviderEnabled`, `enableProvider`, `disableProvider`,
168
- `setProviderPriority`, `setPrimaryProvider`, `disconnectProvider`
169
- - Saved views: `listSavedViews`, `createSavedView`, `deleteSavedView`, `deleteSavedViewById`
170
- - Competitors: `listCompetitors`, `addCompetitor`, `removeCompetitor`, `removeCompetitorById`
171
- - Notification preferences: `getNotificationPreferences`, `updateNotificationPreferences`
172
- - Migration tokens: `listMigrationTokens`, `mintMigrationToken`, `revokeMigrationToken`,
173
- `revokeMigrationTokenById`
151
+ ## Resource namespaces
152
+
153
+ The client groups operations by resource. Existing flat methods remain available as deprecated
154
+ compatibility delegates until 1.0.
155
+
156
+ | Namespace | Methods |
157
+ | - | - |
158
+ | `system` | `getHealth`, `getLiveness`, `getReadiness`, `getCapabilities`, `getOpenApi`, `getLlmsText` |
159
+ | `pricing` | `getRates`, `estimate` |
160
+ | `locations` | `search` |
161
+ | `account` | `get`, `update`, plus `tokens.list`, `tokens.create`, `tokens.revoke` |
162
+ | `projects` | `list`, `create`, `get`, `update`, `delete`, `getDefaults`, `updateDefaults` |
163
+ | `apiKeys` | `list`, `iterate`, `create`, `revoke` |
164
+ | `webhooks` | `list`, `iterate`, `create`, `update`, `delete` |
165
+ | `keywords` | `list`, `iterate`, `add`, `get`, `update`, `setTargetUrl`, `delete`, `bulkUpdate`, `match`, `research`, plus `suggestions.list`, `metrics.get` |
166
+ | `backlinks` | `analyze`, `extendSnapshot` |
167
+ | `rankChecks` | `list`, `iterate`, `run`, `getResult`, plus `history.export`, `history.iterate` |
168
+ | `sitemapMonitors` | `list`, `update` |
169
+ | `signals` | `list`, `iterate`, `create` |
170
+ | `analytics` | `overview.get`, `traffic.list`, `traffic.sync`, `searchPerformance.list` |
171
+ | `alertRules` | `list`, `iterate`, `create`, `update`, `delete` |
172
+ | `alerts` | `list`, `iterate`, `mute`, `markAllRead` |
173
+ | `notificationSettings` | `get`, `update` |
174
+ | `team` | `members.*` and `invites.*` |
175
+ | `providers` | `list`, `iterate`, `connect`, `test`, `updateSettings`, `setEnabled`, `setPriority`, `setPrimary`, `disconnect` |
176
+ | `savedViews` | `list`, `iterate`, `create`, `delete` |
177
+ | `competitors` | `list`, `iterate`, `add`, `remove` |
178
+ | `imports` | `runFromExport`, plus `compatibility.*`, `tokens.*`, `sessions.*` |
179
+
180
+ `apiKeys.list()` and `apiKeys.create()` use the current project selected by authentication. Pass
181
+ `{ projectId }` to select the explicit project route. A personal access token spanning multiple
182
+ projects must pass `projectId` because the top-level route cannot select a project unambiguously.
174
183
 
175
184
  List methods return `{ data, meta }` with `meta.next_cursor`. Resource methods return the resource
176
185
  object directly, matching the Bisibility API response shape.
@@ -179,7 +188,7 @@ Every cursor-paginated list has an `iterate*` counterpart that preserves filters
179
188
  across all pages:
180
189
 
181
190
  ```ts
182
- for await (const keyword of bisibility.iterateKeywords(projectId, { device: "desktop" })) {
191
+ for await (const keyword of bisibility.keywords.iterate(projectId, { device: "desktop" })) {
183
192
  console.log(keyword.text);
184
193
  }
185
194
  ```
@@ -191,12 +200,12 @@ endpoints.
191
200
 
192
201
  ### Keyword research and metrics
193
202
 
194
- `researchKeywords` runs a paid, cached DataForSEO lookup for one seed. Select the research depth
203
+ `keywords.research` runs a paid, cached DataForSEO lookup for one seed. Select the research depth
195
204
  up front with `resultLimit`; this endpoint does not use offset pagination. It requires API write
196
205
  scope because a cache miss can spend the project's provider budget:
197
206
 
198
207
  ```ts
199
- const research = await bisibility.researchKeywords(projectId, {
208
+ const research = await bisibility.keywords.research(projectId, {
200
209
  seed: "rank tracker",
201
210
  mode: "auto",
202
211
  resultLimit: 300,
@@ -208,11 +217,11 @@ const research = await bisibility.researchKeywords(projectId, {
208
217
  Set `estimateOnly: true` for a free cache-aware dry run before a cost-sensitive request. Source
209
218
  diagnostics report `ok`, `failed`, or `skipped`, with a machine-readable reason when applicable.
210
219
 
211
- `getKeywordMetrics` hydrates provider metrics for one to 700 keywords. Its input mirrors the API
220
+ `keywords.metrics.get` hydrates provider metrics for one to 700 keywords. Its input mirrors the API
212
221
  request body, cached rows do not contribute to `cost_cents`, and API write scope is required:
213
222
 
214
223
  ```ts
215
- const metrics = await bisibility.getKeywordMetrics(projectId, {
224
+ const metrics = await bisibility.keywords.metrics.get(projectId, {
216
225
  keywords: ["rank tracker", "seo api"],
217
226
  include_clickstream: false,
218
227
  estimate_only: true,
@@ -228,11 +237,11 @@ provider market does not supply them.
228
237
 
229
238
  ### Project defaults
230
239
 
231
- `updateProjectDefaults(projectId, patch)` sends `PATCH /projects/{id}/defaults` and returns the
240
+ `projects.updateDefaults(projectId, patch)` sends `PATCH /projects/{id}/defaults` and returns the
232
241
  persisted `ProjectDefaults` (default market, schedule, and timezone for new keywords):
233
242
 
234
243
  ```ts
235
- await bisibility.updateProjectDefaults(projectId, {
244
+ await bisibility.projects.updateDefaults(projectId, {
236
245
  country: "United States",
237
246
  device: "desktop",
238
247
  frequency: "daily"
@@ -241,35 +250,35 @@ await bisibility.updateProjectDefaults(projectId, {
241
250
 
242
251
  ### Asynchronous rank checks
243
252
 
244
- `runRankCheck` runs synchronously by default. Pass `async: true` to enqueue the check instead;
253
+ `rankChecks.run` runs synchronously by default. Pass `async: true` to enqueue the check instead;
245
254
  the server responds `202` with a `RankCheck` in `status: "running"` that you can poll via
246
255
  `getRankCheckResult`:
247
256
 
248
257
  ```ts
249
- const queued = await bisibility.runRankCheck(keywordId, undefined, { async: true });
258
+ const queued = await bisibility.rankChecks.run(keywordId, undefined, { async: true });
250
259
  // queued.status === "running"
251
- const result = await bisibility.getRankCheckResult(queued.id);
260
+ const result = await bisibility.rankChecks.getResult(queued.id);
252
261
  ```
253
262
 
254
263
  Failed checks carry `status: "failed"`, an `error` message, and provider fallback `attempts`.
255
264
 
256
265
  ### Signals
257
266
 
258
- `createSignal` ingests a signal (`POST /signals`) into the project tied to your API key;
267
+ `signals.create` ingests a signal (`POST /signals`) into the project tied to your API key;
259
268
  `source` must be `"deploy"`, `"cms"`, or `"api"`, and `type` follows the
260
269
  `category.event` pattern (for example `deploy.completed`). `listSignals(projectId, options)`
261
270
  pages through a project's signals newest first with optional `source`, `type`, `from`, and `to`
262
271
  filters:
263
272
 
264
273
  ```ts
265
- await bisibility.createSignal({
274
+ await bisibility.signals.create({
266
275
  source: "deploy",
267
276
  type: "deploy.completed",
268
277
  payload: { version: "1.2.3" }, // <= 8KB serialized
269
278
  url: "https://example.com/releases/1"
270
279
  });
271
280
 
272
- const recent = await bisibility.listSignals(projectId, {
281
+ const recent = await bisibility.signals.list(projectId, {
273
282
  source: "deploy",
274
283
  from: "2026-07-01T00:00:00.000Z"
275
284
  });
@@ -277,11 +286,11 @@ const recent = await bisibility.listSignals(projectId, {
277
286
 
278
287
  ### Public cost estimates
279
288
 
280
- `getProviderRates` and `getCostEstimate` are anonymous and work without an `apiKey`:
289
+ `pricing.getRates` and `pricing.estimate` are anonymous and work without an `apiKey`:
281
290
 
282
291
  ```ts
283
- const rates = await bisibility.getProviderRates();
284
- const estimate = await bisibility.getCostEstimate({
292
+ const rates = await bisibility.pricing.getRates();
293
+ const estimate = await bisibility.pricing.estimate({
285
294
  keywords: 250,
286
295
  frequency: "daily",
287
296
  provider: "dataforseo",
@@ -293,19 +302,23 @@ const estimate = await bisibility.getCostEstimate({
293
302
  ## Errors
294
303
 
295
304
  All SDK errors extend `BisibilityError`; its concrete subclasses are `BisibilityApiError`,
296
- `BisibilityConfigurationError`, `BisibilityNetworkError`, and `BisibilityResponseError`. The
297
- original RFC problem details body is available on API errors as `error.problem`. API errors also
298
- provide `isRateLimit`, `isNotFound`, and `retryAfterSeconds`. `error.headers` retains ordinary
299
- response headers while credential and cookie headers are removed before the error is exposed to
300
- application logs.
305
+ `BisibilityApiVersionError`, `BisibilityConfigurationError`, `BisibilityNetworkError`, and
306
+ `BisibilityResponseError`. `BisibilityApiVersionError` also extends `BisibilityApiError` and exposes
307
+ the declared version as `declaredApiVersion` plus the server advertisement as
308
+ `serverApiVersions`. The original RFC problem details body is available on API errors as
309
+ `error.problem`. API errors also provide `isRateLimit`, `isNotFound`, and `retryAfterSeconds`.
310
+ `error.headers` retains ordinary response headers while credential and cookie headers are removed
311
+ before the error is exposed to application logs.
301
312
 
302
313
  ```ts
303
- import { BisibilityApiError } from "@bisibility/sdk";
314
+ import { BisibilityApiError, BisibilityApiVersionError } from "@bisibility/sdk";
304
315
 
305
316
  try {
306
- await bisibility.getKeyword("kw_z9y8x7w6v5u4t3s2r1q0p9n8");
317
+ await bisibility.keywords.get("kw_z9y8x7w6v5u4t3s2r1q0p9n8");
307
318
  } catch (error) {
308
- if (error instanceof BisibilityApiError) {
319
+ if (error instanceof BisibilityApiVersionError) {
320
+ console.error(error.declaredApiVersion, error.serverApiVersions);
321
+ } else if (error instanceof BisibilityApiError) {
309
322
  console.error(error.status, error.problem?.detail);
310
323
  }
311
324
  }
@@ -0,0 +1,4 @@
1
+ export declare const BISIBILITY_API_VERSION = "v1";
2
+ export declare const BISIBILITY_API_VERSION_HEADER = "Bisibility-API-Version";
3
+ export declare const UNSUPPORTED_API_VERSION_PROBLEM_TYPE = "https://bisibility.com/problems/unsupported_api_version";
4
+ //# sourceMappingURL=api-version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-version.d.ts","sourceRoot":"","sources":["../src/api-version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAC3C,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AACtE,eAAO,MAAM,oCAAoC,4DACU,CAAC"}
@@ -0,0 +1,4 @@
1
+ export const BISIBILITY_API_VERSION = "v1";
2
+ export const BISIBILITY_API_VERSION_HEADER = "Bisibility-API-Version";
3
+ export const UNSUPPORTED_API_VERSION_PROBLEM_TYPE = "https://bisibility.com/problems/unsupported_api_version";
4
+ //# sourceMappingURL=api-version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-version.js","sourceRoot":"","sources":["../src/api-version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAC3C,MAAM,CAAC,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AACtE,MAAM,CAAC,MAAM,oCAAoC,GAC/C,yDAAyD,CAAC"}