@bisibility/sdk 0.6.1 → 0.7.2

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.2 - 2026-08-02
6
+
7
+ - Added a separate `accessToken` configuration option for OAuth bearer tokens without applying
8
+ API key prefix validation.
9
+
10
+ ## 0.7.1 - 2026-08-02
11
+
12
+ - Republished the 0.7.0 API surface after correcting release validation; runtime behavior is unchanged.
13
+
14
+ ## 0.7.0 - 2026-08-02
15
+
16
+ - **Breaking for typed consumers:** `getHealth()`, `getLiveness()`, and `getReadiness()` now return
17
+ status-only responses; degraded health and readiness HTTP 503 responses return normally without
18
+ retries, while other endpoints retain 503 retries.
19
+ - Added resource-oriented namespaces such as `client.keywords.*`, `client.team.*`, and
20
+ `client.imports.*`; flat methods remain available as deprecated delegates until 1.0.
21
+ - Added typed Saved Keywords list, iterator, create, and delete operations with `svkw` public IDs.
22
+ - Added `Bisibility-API-Version` compatibility declarations, lazy server compatibility checks,
23
+ and `BisibilityApiVersionError` for unsupported newer server contracts.
24
+
3
25
  ## 0.6.1 - 2026-07-30
4
26
 
5
27
  - Improved package metadata to describe the SDK's SEO rank-tracking, keyword, and ranking-history
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,18 @@ 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
+ ```
87
+
88
+ OAuth clients can pass their opaque bearer token as `accessToken`. It is mutually exclusive with
89
+ `apiKey` and does not use API key prefix validation:
90
+
91
+ ```ts
92
+ const bisibility = new BisibilityClient({
93
+ accessToken: oauth.accessToken,
94
+ });
86
95
  ```
87
96
 
88
97
  A custom `fetch` implementation can be injected for older runtimes, proxies, or testing:
@@ -94,7 +103,8 @@ const bisibility = new BisibilityClient({
94
103
  });
95
104
  ```
96
105
 
97
- Protected methods send `Authorization: Bearer <apiKey>`. Write methods accept an optional
106
+ Protected methods send the configured `apiKey` or `accessToken` as `Authorization: Bearer <token>`.
107
+ Write methods accept an optional
98
108
  `idempotencyKey` request option, which maps to the server `Idempotency-Key` header.
99
109
  Requests set `redirect: "error"` so credentials are never forwarded through an HTTP redirect.
100
110
  Custom `fetch` implementations should preserve that behavior.
@@ -112,7 +122,7 @@ up to 60 seconds.
112
122
  Every method accepts per-request options:
113
123
 
114
124
  ```ts
115
- await bisibility.listProjects({
125
+ await bisibility.projects.list({
116
126
  headers: { "X-Request-Id": "..." },
117
127
  signal: controller.signal, // your own AbortSignal
118
128
  timeout: 10_000 // ms; composed with `signal` when both are set
@@ -122,6 +132,15 @@ await bisibility.listProjects({
122
132
  Without an explicit timeout or signal, every attempt has a 30-second timeout. Set `timeout: null`
123
133
  on the client or an individual request to opt out.
124
134
 
135
+ ### API version compatibility
136
+
137
+ The SDK declares `Bisibility-API-Version: v1` on every request. Before its first ordinary API
138
+ operation, each client lazily checks `/capabilities` once; calling `getCapabilities()` first
139
+ satisfies the same check without a duplicate request. A server that advertises `apiVersions` but
140
+ does not serve `v1` fails with `BisibilityApiVersionError` before the requested operation runs.
141
+ Older servers whose capabilities response has no `apiVersions` field remain compatible, and the
142
+ original request continues normally.
143
+
125
144
  ## Public resource IDs
126
145
 
127
146
  Every resource identifier accepted or returned by the SDK uses public ID v3. The
@@ -139,38 +158,38 @@ Locations are identified by `location_key`; they do not expose a location ID.
139
158
  Cloud import and export payloads use schema version 5 only. Pagination cursors are opaque SDK
140
159
  values; v3 API cursors returned by the server must be passed back unchanged.
141
160
 
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`
161
+ ## Resource namespaces
162
+
163
+ The client groups operations by resource. Existing flat methods remain available as deprecated
164
+ compatibility delegates until 1.0.
165
+
166
+ | Namespace | Methods |
167
+ | - | - |
168
+ | `system` | `getHealth`, `getLiveness`, `getReadiness`, `getCapabilities`, `getOpenApi`, `getLlmsText` |
169
+ | `pricing` | `getRates`, `estimate` |
170
+ | `locations` | `search` |
171
+ | `account` | `get`, `update`, plus `tokens.list`, `tokens.create`, `tokens.revoke` |
172
+ | `projects` | `list`, `create`, `get`, `update`, `delete`, `getDefaults`, `updateDefaults` |
173
+ | `apiKeys` | `list`, `iterate`, `create`, `revoke` |
174
+ | `webhooks` | `list`, `iterate`, `create`, `update`, `delete` |
175
+ | `keywords` | `list`, `iterate`, `add`, `get`, `update`, `setTargetUrl`, `delete`, `bulkUpdate`, `match`, `research`, plus `suggestions.list`, `metrics.get` |
176
+ | `backlinks` | `analyze`, `extendSnapshot` |
177
+ | `rankChecks` | `list`, `iterate`, `run`, `getResult`, plus `history.export`, `history.iterate` |
178
+ | `sitemapMonitors` | `list`, `update` |
179
+ | `signals` | `list`, `iterate`, `create` |
180
+ | `analytics` | `overview.get`, `traffic.list`, `traffic.sync`, `searchPerformance.list` |
181
+ | `alertRules` | `list`, `iterate`, `create`, `update`, `delete` |
182
+ | `alerts` | `list`, `iterate`, `mute`, `markAllRead` |
183
+ | `notificationSettings` | `get`, `update` |
184
+ | `team` | `members.*` and `invites.*` |
185
+ | `providers` | `list`, `iterate`, `connect`, `test`, `updateSettings`, `setEnabled`, `setPriority`, `setPrimary`, `disconnect` |
186
+ | `savedViews` | `list`, `iterate`, `create`, `delete` |
187
+ | `competitors` | `list`, `iterate`, `add`, `remove` |
188
+ | `imports` | `runFromExport`, plus `compatibility.*`, `tokens.*`, `sessions.*` |
189
+
190
+ `apiKeys.list()` and `apiKeys.create()` use the current project selected by authentication. Pass
191
+ `{ projectId }` to select the explicit project route. A personal access token spanning multiple
192
+ projects must pass `projectId` because the top-level route cannot select a project unambiguously.
174
193
 
175
194
  List methods return `{ data, meta }` with `meta.next_cursor`. Resource methods return the resource
176
195
  object directly, matching the Bisibility API response shape.
@@ -179,7 +198,7 @@ Every cursor-paginated list has an `iterate*` counterpart that preserves filters
179
198
  across all pages:
180
199
 
181
200
  ```ts
182
- for await (const keyword of bisibility.iterateKeywords(projectId, { device: "desktop" })) {
201
+ for await (const keyword of bisibility.keywords.iterate(projectId, { device: "desktop" })) {
183
202
  console.log(keyword.text);
184
203
  }
185
204
  ```
@@ -191,12 +210,12 @@ endpoints.
191
210
 
192
211
  ### Keyword research and metrics
193
212
 
194
- `researchKeywords` runs a paid, cached DataForSEO lookup for one seed. Select the research depth
213
+ `keywords.research` runs a paid, cached DataForSEO lookup for one seed. Select the research depth
195
214
  up front with `resultLimit`; this endpoint does not use offset pagination. It requires API write
196
215
  scope because a cache miss can spend the project's provider budget:
197
216
 
198
217
  ```ts
199
- const research = await bisibility.researchKeywords(projectId, {
218
+ const research = await bisibility.keywords.research(projectId, {
200
219
  seed: "rank tracker",
201
220
  mode: "auto",
202
221
  resultLimit: 300,
@@ -208,11 +227,11 @@ const research = await bisibility.researchKeywords(projectId, {
208
227
  Set `estimateOnly: true` for a free cache-aware dry run before a cost-sensitive request. Source
209
228
  diagnostics report `ok`, `failed`, or `skipped`, with a machine-readable reason when applicable.
210
229
 
211
- `getKeywordMetrics` hydrates provider metrics for one to 700 keywords. Its input mirrors the API
230
+ `keywords.metrics.get` hydrates provider metrics for one to 700 keywords. Its input mirrors the API
212
231
  request body, cached rows do not contribute to `cost_cents`, and API write scope is required:
213
232
 
214
233
  ```ts
215
- const metrics = await bisibility.getKeywordMetrics(projectId, {
234
+ const metrics = await bisibility.keywords.metrics.get(projectId, {
216
235
  keywords: ["rank tracker", "seo api"],
217
236
  include_clickstream: false,
218
237
  estimate_only: true,
@@ -228,11 +247,11 @@ provider market does not supply them.
228
247
 
229
248
  ### Project defaults
230
249
 
231
- `updateProjectDefaults(projectId, patch)` sends `PATCH /projects/{id}/defaults` and returns the
250
+ `projects.updateDefaults(projectId, patch)` sends `PATCH /projects/{id}/defaults` and returns the
232
251
  persisted `ProjectDefaults` (default market, schedule, and timezone for new keywords):
233
252
 
234
253
  ```ts
235
- await bisibility.updateProjectDefaults(projectId, {
254
+ await bisibility.projects.updateDefaults(projectId, {
236
255
  country: "United States",
237
256
  device: "desktop",
238
257
  frequency: "daily"
@@ -241,35 +260,35 @@ await bisibility.updateProjectDefaults(projectId, {
241
260
 
242
261
  ### Asynchronous rank checks
243
262
 
244
- `runRankCheck` runs synchronously by default. Pass `async: true` to enqueue the check instead;
263
+ `rankChecks.run` runs synchronously by default. Pass `async: true` to enqueue the check instead;
245
264
  the server responds `202` with a `RankCheck` in `status: "running"` that you can poll via
246
265
  `getRankCheckResult`:
247
266
 
248
267
  ```ts
249
- const queued = await bisibility.runRankCheck(keywordId, undefined, { async: true });
268
+ const queued = await bisibility.rankChecks.run(keywordId, undefined, { async: true });
250
269
  // queued.status === "running"
251
- const result = await bisibility.getRankCheckResult(queued.id);
270
+ const result = await bisibility.rankChecks.getResult(queued.id);
252
271
  ```
253
272
 
254
273
  Failed checks carry `status: "failed"`, an `error` message, and provider fallback `attempts`.
255
274
 
256
275
  ### Signals
257
276
 
258
- `createSignal` ingests a signal (`POST /signals`) into the project tied to your API key;
277
+ `signals.create` ingests a signal (`POST /signals`) into the project tied to your API key;
259
278
  `source` must be `"deploy"`, `"cms"`, or `"api"`, and `type` follows the
260
279
  `category.event` pattern (for example `deploy.completed`). `listSignals(projectId, options)`
261
280
  pages through a project's signals newest first with optional `source`, `type`, `from`, and `to`
262
281
  filters:
263
282
 
264
283
  ```ts
265
- await bisibility.createSignal({
284
+ await bisibility.signals.create({
266
285
  source: "deploy",
267
286
  type: "deploy.completed",
268
287
  payload: { version: "1.2.3" }, // <= 8KB serialized
269
288
  url: "https://example.com/releases/1"
270
289
  });
271
290
 
272
- const recent = await bisibility.listSignals(projectId, {
291
+ const recent = await bisibility.signals.list(projectId, {
273
292
  source: "deploy",
274
293
  from: "2026-07-01T00:00:00.000Z"
275
294
  });
@@ -277,11 +296,11 @@ const recent = await bisibility.listSignals(projectId, {
277
296
 
278
297
  ### Public cost estimates
279
298
 
280
- `getProviderRates` and `getCostEstimate` are anonymous and work without an `apiKey`:
299
+ `pricing.getRates` and `pricing.estimate` are anonymous and work without an `apiKey`:
281
300
 
282
301
  ```ts
283
- const rates = await bisibility.getProviderRates();
284
- const estimate = await bisibility.getCostEstimate({
302
+ const rates = await bisibility.pricing.getRates();
303
+ const estimate = await bisibility.pricing.estimate({
285
304
  keywords: 250,
286
305
  frequency: "daily",
287
306
  provider: "dataforseo",
@@ -293,19 +312,23 @@ const estimate = await bisibility.getCostEstimate({
293
312
  ## Errors
294
313
 
295
314
  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.
315
+ `BisibilityApiVersionError`, `BisibilityConfigurationError`, `BisibilityNetworkError`, and
316
+ `BisibilityResponseError`. `BisibilityApiVersionError` also extends `BisibilityApiError` and exposes
317
+ the declared version as `declaredApiVersion` plus the server advertisement as
318
+ `serverApiVersions`. The original RFC problem details body is available on API errors as
319
+ `error.problem`. API errors also provide `isRateLimit`, `isNotFound`, and `retryAfterSeconds`.
320
+ `error.headers` retains ordinary response headers while credential and cookie headers are removed
321
+ before the error is exposed to application logs.
301
322
 
302
323
  ```ts
303
- import { BisibilityApiError } from "@bisibility/sdk";
324
+ import { BisibilityApiError, BisibilityApiVersionError } from "@bisibility/sdk";
304
325
 
305
326
  try {
306
- await bisibility.getKeyword("kw_z9y8x7w6v5u4t3s2r1q0p9n8");
327
+ await bisibility.keywords.get("kw_z9y8x7w6v5u4t3s2r1q0p9n8");
307
328
  } catch (error) {
308
- if (error instanceof BisibilityApiError) {
329
+ if (error instanceof BisibilityApiVersionError) {
330
+ console.error(error.declaredApiVersion, error.serverApiVersions);
331
+ } else if (error instanceof BisibilityApiError) {
309
332
  console.error(error.status, error.problem?.detail);
310
333
  }
311
334
  }
@@ -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"}