@qverisai/sdk 0.2.0 → 0.4.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 +45 -0
- package/LICENSE +1 -1
- package/README.md +70 -3
- package/dist/client.d.ts +12 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +145 -105
- package/dist/client.js.map +1 -1
- package/dist/integrations/ai.d.ts +768 -0
- package/dist/integrations/ai.d.ts.map +1 -0
- package/dist/integrations/ai.js +80 -0
- package/dist/integrations/ai.js.map +1 -0
- package/dist/retry.d.ts +42 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +63 -0
- package/dist/retry.js.map +1 -0
- package/dist/types.d.ts +7 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +38 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@qverisai/sdk` are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow [Semantic Versioning](https://semver.org/).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.4.0] - 2026-07-14
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Changed the public endpoint configuration contract to deterministic selection: explicit `baseUrl` overrides `QVERIS_BASE_URL`, which overrides the built-in default. API keys and legacy region settings no longer reroute requests, and endpoint overrides are validated before use. ([#204])
|
|
14
|
+
- Upgraded the Vitest and coverage toolchain to audited Node.js 18-compatible releases and pinned the Vite 6 security floor used by tests. Published runtime dependencies are unchanged. ([#211])
|
|
15
|
+
- Raised `engines.node` to `>=18.2.0`, aligning every package on the toolkit's minimum-supported Node (the MCP server requires 18.2 for `closeAllConnections`). ([#161])
|
|
16
|
+
|
|
17
|
+
## [0.3.0] - 2026-07-09
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Vercel AI SDK adapter: `getQverisTools(qveris)` from `@qverisai/sdk/ai` returns `qveris_discover` / `qveris_inspect` / `qveris_call` tools for `generateText`/`streamText` (`ai` and `zod` as optional peer dependencies). ([#134])
|
|
22
|
+
- Rate-limited (`429`) and transient (`503`) responses are retried automatically: honors `Retry-After`, otherwise exponential backoff with jitter, bounded by the `maxRetries` config option (default 3; `0` disables); `rateLimitRetryCount` exposes the backoff. ([#143])
|
|
23
|
+
|
|
24
|
+
## [0.2.0] - 2026-07-06
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- First release of the typed QVeris REST client: `discover` / `inspect` / `call` / `credits` / `usage` / `ledger`, zero dependencies (native fetch, Node 18+). ([#106])
|
|
29
|
+
- Wire semantics aligned with the Python SDK and MCP server: success-envelope unwrapping, region auto-detection from the key prefix, structured `QverisApiError` with observability context.
|
|
30
|
+
- Response types cover category objects, capability descriptors, `why_recommended`, and `expected_cost`.
|
|
31
|
+
|
|
32
|
+
### Note
|
|
33
|
+
|
|
34
|
+
- `0.1.x` under this npm name was an early MCP-focused SDK, superseded by `@qverisai/mcp`.
|
|
35
|
+
|
|
36
|
+
[Unreleased]: https://github.com/QVerisAI/qveris-agent-toolkit/compare/js-sdk-v0.4.0...HEAD
|
|
37
|
+
[0.4.0]: https://github.com/QVerisAI/qveris-agent-toolkit/compare/js-sdk-v0.3.0...js-sdk-v0.4.0
|
|
38
|
+
[0.3.0]: https://github.com/QVerisAI/qveris-agent-toolkit/compare/js-sdk-v0.2.0...js-sdk-v0.3.0
|
|
39
|
+
[0.2.0]: https://github.com/QVerisAI/qveris-agent-toolkit/releases/tag/js-sdk-v0.2.0
|
|
40
|
+
[#204]: https://github.com/QVerisAI/qveris-agent-toolkit/issues/204
|
|
41
|
+
[#211]: https://github.com/QVerisAI/qveris-agent-toolkit/issues/211
|
|
42
|
+
[#161]: https://github.com/QVerisAI/qveris-agent-toolkit/issues/161
|
|
43
|
+
[#143]: https://github.com/QVerisAI/qveris-agent-toolkit/pull/143
|
|
44
|
+
[#134]: https://github.com/QVerisAI/qveris-agent-toolkit/pull/134
|
|
45
|
+
[#106]: https://github.com/QVerisAI/qveris-agent-toolkit/issues/106
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -52,14 +52,51 @@ const ledger = await qveris.ledger({ direction: 'consume', summary: true });
|
|
|
52
52
|
const credits = await qveris.credits();
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
## API reference
|
|
56
|
+
|
|
57
|
+
Construct with `new Qveris({ apiKey })` or `Qveris.fromEnv(overrides?)` (reads
|
|
58
|
+
`QVERIS_API_KEY` and resolves the API endpoint automatically).
|
|
59
|
+
|
|
60
|
+
| Method | Billed | Returns | Notes |
|
|
61
|
+
| --- | --- | --- | --- |
|
|
62
|
+
| `discover(query, options?)` | Free | `SearchResponse` | `options`: `limit`, `sessionId`, `timeoutMs`. Results carry `why_recommended`, `expected_cost`, `stats`. |
|
|
63
|
+
| `inspect(toolIds, options?)` | Free | `SearchResponse` | `toolIds` is one id or an array; `options`: `searchId`, `sessionId`, `timeoutMs`. An empty array resolves locally with no request. |
|
|
64
|
+
| `call(toolId, options)` | Credits | `ExecuteResponse` | `options`: `parameters` (required), `searchId`, `maxResponseSize`, `sessionId`, `timeoutMs`. |
|
|
65
|
+
| `credits()` | Free | `CreditsResponse` | Current balance and bucket details. |
|
|
66
|
+
| `usage(filters?)` | Free | `UsageEventsResponse` | Request-level audit; filter by `execution_id`, `search_id`, dates, `summary`, `limit`. |
|
|
67
|
+
| `ledger(filters?)` | Free | `CreditsLedgerResponse` | Settled credit movements; filter by `direction`, dates, `summary`, `limit`. |
|
|
68
|
+
|
|
69
|
+
Read-only members: `qveris.rateLimitRetryCount` (see [Rate limiting](#rate-limiting--retries)).
|
|
70
|
+
|
|
71
|
+
Key response fields:
|
|
72
|
+
|
|
73
|
+
- **`SearchResponse`** — `search_id`, `total`, `results: ToolInfo[]` (`tool_id`, `name`, `description`, `params`, `examples.sample_parameters`, `stats.success_rate`, `stats.avg_execution_time_ms`, `expected_cost`, `why_recommended`).
|
|
74
|
+
- **`ExecuteResponse`** — `execution_id`, `success`, `result`, `billing` (pre-settlement estimate; the final charge is in `usage()` / `ledger()`).
|
|
75
|
+
|
|
76
|
+
All types are exported from the package root (`import type { SearchResponse, ExecuteResponse, ToolInfo } from '@qverisai/sdk'`).
|
|
77
|
+
|
|
55
78
|
## Configuration
|
|
56
79
|
|
|
57
80
|
| Option / env var | Description |
|
|
58
81
|
| --- | --- |
|
|
59
|
-
| `apiKey` / `QVERIS_API_KEY` | Required. Create one at [qveris.ai](https://qveris.ai/account?page=api-keys)
|
|
60
|
-
| `baseUrl` / `QVERIS_BASE_URL` |
|
|
61
|
-
| `QVERIS_REGION` | Force region: `global` or `cn`. Otherwise auto-detected from the key prefix (`sk-cn-…` → China) |
|
|
82
|
+
| `apiKey` / `QVERIS_API_KEY` | Required. Create one at [qveris.ai](https://qveris.ai/account?page=api-keys) |
|
|
83
|
+
| `baseUrl` / `QVERIS_BASE_URL` | API endpoint: constructor option > environment variable > built-in default |
|
|
62
84
|
| `timeoutMs` | Default request timeout (30s; `call` defaults to 120s) |
|
|
85
|
+
| `maxRetries` | Retries for rate-limited (429) / transient (503) responses (default 3; `0` disables) |
|
|
86
|
+
|
|
87
|
+
API keys never select the endpoint. Endpoint overrides must be HTTP(S) URLs without credentials, a query string, or a fragment.
|
|
88
|
+
|
|
89
|
+
## Rate limiting & retries
|
|
90
|
+
|
|
91
|
+
The client transparently retries rate-limited (`429`) and transient (`503`) responses: it honors the `Retry-After` header when present, otherwise backs off exponentially with full jitter. Each wait is capped and retries are bounded by `maxRetries`, so a call never hangs.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
const qveris = new Qveris({ apiKey: process.env.QVERIS_API_KEY!, maxRetries: 5 });
|
|
95
|
+
// ... after some calls under load:
|
|
96
|
+
qveris.rateLimitRetryCount; // how many times it backed off (pressure, not failures)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Set `maxRetries: 0` to disable. Rate-limit backoff is retried pressure rather than failure — read `rateLimitRetryCount` to observe it instead of treating the retried `429`s as errors.
|
|
63
100
|
|
|
64
101
|
## Errors
|
|
65
102
|
|
|
@@ -77,6 +114,36 @@ try {
|
|
|
77
114
|
}
|
|
78
115
|
```
|
|
79
116
|
|
|
117
|
+
## Framework integrations
|
|
118
|
+
|
|
119
|
+
Expose the QVeris workflow as [Vercel AI SDK](https://sdk.vercel.ai) tools. `ai` and `zod` are peer dependencies:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
npm install @qverisai/sdk ai zod
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { generateText, stepCountIs } from 'ai';
|
|
127
|
+
import { openai } from '@ai-sdk/openai';
|
|
128
|
+
import { Qveris } from '@qverisai/sdk';
|
|
129
|
+
import { getQverisTools } from '@qverisai/sdk/ai';
|
|
130
|
+
|
|
131
|
+
const qveris = new Qveris({ apiKey: process.env.QVERIS_API_KEY! });
|
|
132
|
+
const { text } = await generateText({
|
|
133
|
+
model: openai('gpt-4o'),
|
|
134
|
+
tools: getQverisTools(qveris), // qveris_discover / qveris_inspect / qveris_call
|
|
135
|
+
stopWhen: stepCountIs(6),
|
|
136
|
+
prompt: 'Find a stock quote capability and quote AAPL.',
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Examples
|
|
141
|
+
|
|
142
|
+
Runnable scripts in [`examples/`](examples): the discover → inspect → call
|
|
143
|
+
quickstart, a Vercel AI SDK agent, and rate-limit/observability. Each is safe to
|
|
144
|
+
run without an API key (it explains how to set one), and any credit-spending
|
|
145
|
+
call is gated behind `RUN_QVERIS_CALLS=1`.
|
|
146
|
+
|
|
80
147
|
## Version history note
|
|
81
148
|
|
|
82
149
|
Versions `0.1.x` of this npm package were an early MCP-focused SDK, since superseded by [`@qverisai/mcp`](https://www.npmjs.com/package/@qverisai/mcp). The typed REST client documented here starts at **`0.2.0`**.
|
package/dist/client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* QVeris API client.
|
|
3
3
|
*
|
|
4
4
|
* A lightweight, dependency-free typed client for the QVeris REST API using
|
|
5
|
-
* native fetch (Node.js 18+). Handles authentication,
|
|
5
|
+
* native fetch (Node.js 18+). Handles authentication, endpoint resolution,
|
|
6
6
|
* success-envelope unwrapping, timeouts, and error normalization.
|
|
7
7
|
*
|
|
8
8
|
* The wire semantics mirror the Python SDK (`qveris` on PyPI) and the MCP
|
|
@@ -64,11 +64,20 @@ export declare class Qveris {
|
|
|
64
64
|
private readonly apiKey;
|
|
65
65
|
private readonly baseUrl;
|
|
66
66
|
private readonly defaultTimeoutMs;
|
|
67
|
+
private readonly maxRetries;
|
|
68
|
+
private rateLimitRetries;
|
|
67
69
|
constructor(config: QverisClientConfig);
|
|
70
|
+
/**
|
|
71
|
+
* How many times the client has backed off on a rate-limited (429) /
|
|
72
|
+
* transient (503) response so far. Rate-limit backoff is retried pressure,
|
|
73
|
+
* not failure — observe this rather than counting the retried responses.
|
|
74
|
+
*/
|
|
75
|
+
get rateLimitRetryCount(): number;
|
|
76
|
+
/** Sleep for `ms` (a seam so tests can stub out the wait). */
|
|
77
|
+
private sleep;
|
|
68
78
|
/**
|
|
69
79
|
* Create a client from the QVERIS_API_KEY environment variable.
|
|
70
|
-
*
|
|
71
|
-
* overridden via QVERIS_REGION / QVERIS_BASE_URL.
|
|
80
|
+
* An explicit baseUrl override takes priority over QVERIS_BASE_URL.
|
|
72
81
|
*/
|
|
73
82
|
static fromEnv(overrides?: Omit<QverisClientConfig, 'apiKey'>): Qveris;
|
|
74
83
|
/**
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAWH,OAAO,KAAK,EAEV,QAAQ,EAGR,oBAAoB,EACpB,qBAAqB,EACrB,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AA8CpB,2CAA2C;AAC3C,MAAM,WAAW,eAAe;IAC9B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,MAAM,EAAE,kBAAkB;IAUtC;;;;OAIG;IACH,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,8DAA8D;YAChD,KAAK;IAKnB;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GAAG,MAAM;IAUtE;;OAEG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC;IAcrF;;;OAGG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,cAAc,CAAC;IAkBhG;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC;IAiB1E,qDAAqD;IAC/C,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC;IAIzC,+CAA+C;IACzC,KAAK,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAW5E,0CAA0C;IACpC,MAAM,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAWhF;;OAEG;YACW,OAAO;IAqIrB;;;;OAIG;IACH,OAAO,CAAC,cAAc;CAqBvB;AA+BD,YAAY,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/client.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* QVeris API client.
|
|
3
3
|
*
|
|
4
4
|
* A lightweight, dependency-free typed client for the QVeris REST API using
|
|
5
|
-
* native fetch (Node.js 18+). Handles authentication,
|
|
5
|
+
* native fetch (Node.js 18+). Handles authentication, endpoint resolution,
|
|
6
6
|
* success-envelope unwrapping, timeouts, and error normalization.
|
|
7
7
|
*
|
|
8
8
|
* The wire semantics mirror the Python SDK (`qveris` on PyPI) and the MCP
|
|
@@ -11,34 +11,43 @@
|
|
|
11
11
|
* @module client
|
|
12
12
|
*/
|
|
13
13
|
import { QverisApiError } from './errors.js';
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
global: 'https://qveris.ai/api/v1',
|
|
17
|
-
cn: 'https://qveris.cn/api/v1',
|
|
18
|
-
};
|
|
19
|
-
/**
|
|
20
|
-
* Detect region from API key prefix.
|
|
21
|
-
* sk-cn-xxx -> cn, sk-xxx -> global
|
|
22
|
-
*/
|
|
23
|
-
function detectRegionFromKey(apiKey) {
|
|
24
|
-
return apiKey.startsWith('sk-cn-') ? 'cn' : 'global';
|
|
25
|
-
}
|
|
14
|
+
import { computeRetryDelayMs, DEFAULT_BASE_DELAY_MS, DEFAULT_MAX_DELAY_MS, parseRetryAfterMs, resolveMaxRetries, RETRYABLE_STATUS, } from './retry.js';
|
|
15
|
+
const DEFAULT_BASE_URL = 'https://qveris.ai/api/v1';
|
|
26
16
|
/**
|
|
27
17
|
* Resolve the base URL for the QVeris API.
|
|
28
|
-
* Priority: explicit baseUrl > QVERIS_BASE_URL env >
|
|
18
|
+
* Priority: explicit baseUrl > QVERIS_BASE_URL env > built-in default.
|
|
19
|
+
* API keys and QVERIS_REGION never affect endpoint selection.
|
|
29
20
|
*/
|
|
30
|
-
function resolveBaseUrl(
|
|
31
|
-
if (explicitBaseUrl)
|
|
32
|
-
return explicitBaseUrl
|
|
33
|
-
if (typeof process !== 'undefined') {
|
|
34
|
-
|
|
35
|
-
return process.env.QVERIS_BASE_URL.replace(/\/+$/, '');
|
|
36
|
-
if (process.env.QVERIS_REGION) {
|
|
37
|
-
const region = process.env.QVERIS_REGION.toLowerCase();
|
|
38
|
-
return REGION_URLS[region] ?? REGION_URLS.global;
|
|
39
|
-
}
|
|
21
|
+
function resolveBaseUrl(explicitBaseUrl) {
|
|
22
|
+
if (explicitBaseUrl !== undefined)
|
|
23
|
+
return normalizeBaseUrl(explicitBaseUrl);
|
|
24
|
+
if (typeof process !== 'undefined' && typeof process.env?.QVERIS_BASE_URL === 'string') {
|
|
25
|
+
return normalizeBaseUrl(process.env.QVERIS_BASE_URL);
|
|
40
26
|
}
|
|
41
|
-
return
|
|
27
|
+
return DEFAULT_BASE_URL;
|
|
28
|
+
}
|
|
29
|
+
function normalizeBaseUrl(value) {
|
|
30
|
+
const candidate = value.trim();
|
|
31
|
+
if (!candidate)
|
|
32
|
+
throw new Error('QVeris API base URL must not be empty');
|
|
33
|
+
if (!/^https?:\/\/[^/?#\s\\]/i.test(candidate) || /\s/.test(candidate) || candidate.includes('\\')) {
|
|
34
|
+
throw new Error('QVeris API base URL must be a valid HTTP(S) URL');
|
|
35
|
+
}
|
|
36
|
+
let url;
|
|
37
|
+
try {
|
|
38
|
+
url = new URL(candidate);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
throw new Error('QVeris API base URL must be a valid HTTP(S) URL');
|
|
42
|
+
}
|
|
43
|
+
if (!['http:', 'https:'].includes(url.protocol) || !url.hostname) {
|
|
44
|
+
throw new Error('QVeris API base URL must be a valid HTTP(S) URL');
|
|
45
|
+
}
|
|
46
|
+
if (url.username || url.password || candidate.includes('?') || candidate.includes('#')) {
|
|
47
|
+
throw new Error('QVeris API base URL must not contain credentials, a query, or a fragment');
|
|
48
|
+
}
|
|
49
|
+
url.pathname = url.pathname.replace(/\/+$/, '');
|
|
50
|
+
return url.toString().replace(/\/$/, '');
|
|
42
51
|
}
|
|
43
52
|
/** Default timeout: 30s for discover/inspect/audit, 120s for call */
|
|
44
53
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
@@ -65,27 +74,39 @@ export class Qveris {
|
|
|
65
74
|
apiKey;
|
|
66
75
|
baseUrl;
|
|
67
76
|
defaultTimeoutMs;
|
|
77
|
+
maxRetries;
|
|
78
|
+
rateLimitRetries = 0;
|
|
68
79
|
constructor(config) {
|
|
69
80
|
if (!config.apiKey) {
|
|
70
|
-
throw new Error('QVeris API key is required.\n' +
|
|
71
|
-
'Global: https://qveris.ai/account?page=api-keys\n' +
|
|
72
|
-
'China: https://qveris.cn/account?page=api-keys');
|
|
81
|
+
throw new Error('QVeris API key is required.\n' + 'Create one at https://qveris.ai/account?page=api-keys');
|
|
73
82
|
}
|
|
74
83
|
this.apiKey = config.apiKey;
|
|
75
|
-
this.baseUrl = resolveBaseUrl(config.
|
|
84
|
+
this.baseUrl = resolveBaseUrl(config.baseUrl);
|
|
76
85
|
this.defaultTimeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
86
|
+
this.maxRetries = resolveMaxRetries(config.maxRetries);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* How many times the client has backed off on a rate-limited (429) /
|
|
90
|
+
* transient (503) response so far. Rate-limit backoff is retried pressure,
|
|
91
|
+
* not failure — observe this rather than counting the retried responses.
|
|
92
|
+
*/
|
|
93
|
+
get rateLimitRetryCount() {
|
|
94
|
+
return this.rateLimitRetries;
|
|
95
|
+
}
|
|
96
|
+
/** Sleep for `ms` (a seam so tests can stub out the wait). */
|
|
97
|
+
async sleep(ms) {
|
|
98
|
+
if (ms <= 0)
|
|
99
|
+
return;
|
|
100
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
101
|
}
|
|
78
102
|
/**
|
|
79
103
|
* Create a client from the QVERIS_API_KEY environment variable.
|
|
80
|
-
*
|
|
81
|
-
* overridden via QVERIS_REGION / QVERIS_BASE_URL.
|
|
104
|
+
* An explicit baseUrl override takes priority over QVERIS_BASE_URL.
|
|
82
105
|
*/
|
|
83
106
|
static fromEnv(overrides) {
|
|
84
107
|
const apiKey = process.env.QVERIS_API_KEY;
|
|
85
108
|
if (!apiKey) {
|
|
86
|
-
throw new Error('QVERIS_API_KEY environment variable is required.\n' +
|
|
87
|
-
'Global: https://qveris.ai/account?page=api-keys\n' +
|
|
88
|
-
'China: https://qveris.cn/account?page=api-keys');
|
|
109
|
+
throw new Error('QVERIS_API_KEY environment variable is required.\n' + 'Create one at https://qveris.ai/account?page=api-keys');
|
|
89
110
|
}
|
|
90
111
|
return new Qveris({ apiKey, ...overrides });
|
|
91
112
|
}
|
|
@@ -152,7 +173,6 @@ export class Qveris {
|
|
|
152
173
|
}
|
|
153
174
|
}
|
|
154
175
|
}
|
|
155
|
-
const controller = new AbortController();
|
|
156
176
|
const resolvedTimeoutMs = timeoutMs ?? this.defaultTimeoutMs;
|
|
157
177
|
const queryParams = Object.fromEntries(url.searchParams.entries());
|
|
158
178
|
const requestContext = {
|
|
@@ -164,80 +184,103 @@ export class Qveris {
|
|
|
164
184
|
...(Object.keys(queryParams).length > 0 && { query_params: queryParams }),
|
|
165
185
|
timeout_ms: resolvedTimeoutMs,
|
|
166
186
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
// Retry rate-limited (429) / transient (503) responses: honor Retry-After,
|
|
188
|
+
// otherwise exponential backoff with jitter, bounded by maxRetries. Each
|
|
189
|
+
// attempt is a fresh fetch with its own timeout.
|
|
190
|
+
for (let attempt = 0;; attempt++) {
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timeout = setTimeout(() => controller.abort(), resolvedTimeoutMs);
|
|
193
|
+
// eslint-disable-next-line no-useless-assignment -- TS definite-assignment needs the init across try/finally
|
|
194
|
+
let retryDelayMs = null;
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(url.toString(), {
|
|
197
|
+
method,
|
|
198
|
+
headers: {
|
|
199
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
},
|
|
202
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
203
|
+
signal: controller.signal,
|
|
204
|
+
});
|
|
205
|
+
if (RETRYABLE_STATUS.has(response.status) && attempt < this.maxRetries) {
|
|
206
|
+
retryDelayMs = computeRetryDelayMs({
|
|
207
|
+
retryAfterMs: parseRetryAfterMs(response.headers.get('retry-after')),
|
|
208
|
+
attempt,
|
|
209
|
+
baseDelayMs: DEFAULT_BASE_DELAY_MS,
|
|
210
|
+
maxDelayMs: DEFAULT_MAX_DELAY_MS,
|
|
211
|
+
});
|
|
212
|
+
// Discard the body so the connection is released before we retry.
|
|
213
|
+
// (`.cancel?.()` so a body without cancel — e.g. a test double —
|
|
214
|
+
// can't throw here and mask the rate-limit as a network error.)
|
|
215
|
+
await response.body?.cancel?.().catch(() => undefined);
|
|
216
|
+
this.rateLimitRetries++;
|
|
190
217
|
}
|
|
191
|
-
|
|
192
|
-
|
|
218
|
+
else if (!response.ok) {
|
|
219
|
+
const status = response.status;
|
|
220
|
+
let errorMessage;
|
|
221
|
+
let errorDetails;
|
|
222
|
+
try {
|
|
223
|
+
const errorBody = (await response.json());
|
|
224
|
+
errorMessage =
|
|
225
|
+
errorBody.error_message ||
|
|
226
|
+
errorBody.message ||
|
|
227
|
+
errorBody.error ||
|
|
228
|
+
response.statusText;
|
|
229
|
+
errorDetails = errorBody;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
errorMessage = response.statusText || `HTTP ${status}`;
|
|
233
|
+
}
|
|
234
|
+
if (status === 402) {
|
|
235
|
+
const pricingHost = this.baseUrl.includes('qveris.cn') ? 'https://qveris.cn' : 'https://qveris.ai';
|
|
236
|
+
errorMessage = `Insufficient credits. ${errorMessage}. Purchase credits at ${pricingHost}/pricing`;
|
|
237
|
+
}
|
|
238
|
+
throw new QverisApiError({
|
|
239
|
+
status,
|
|
240
|
+
message: errorMessage,
|
|
241
|
+
...(errorDetails !== undefined && { details: errorDetails }),
|
|
242
|
+
observability: withErrorContext(requestContext, 'http_error', status, extractRequestId(response)),
|
|
243
|
+
});
|
|
193
244
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
245
|
+
else {
|
|
246
|
+
let payload;
|
|
247
|
+
try {
|
|
248
|
+
payload = await response.json();
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
throw new QverisApiError({
|
|
252
|
+
status: response.status,
|
|
253
|
+
message: 'Invalid or empty JSON response from API',
|
|
254
|
+
observability: withErrorContext(requestContext, 'invalid_json', response.status, extractRequestId(response)),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
return this.unwrapEnvelope(payload, requestContext);
|
|
199
258
|
}
|
|
200
|
-
throw new QverisApiError({
|
|
201
|
-
status,
|
|
202
|
-
message: errorMessage,
|
|
203
|
-
...(errorDetails !== undefined && { details: errorDetails }),
|
|
204
|
-
observability: withErrorContext(requestContext, 'http_error', status, extractRequestId(response)),
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
let payload;
|
|
208
|
-
try {
|
|
209
|
-
payload = await response.json();
|
|
210
|
-
}
|
|
211
|
-
catch {
|
|
212
|
-
throw new QverisApiError({
|
|
213
|
-
status: response.status,
|
|
214
|
-
message: 'Invalid or empty JSON response from API',
|
|
215
|
-
observability: withErrorContext(requestContext, 'invalid_json', response.status, extractRequestId(response)),
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
return this.unwrapEnvelope(payload, requestContext);
|
|
219
|
-
}
|
|
220
|
-
catch (err) {
|
|
221
|
-
if (err instanceof QverisApiError) {
|
|
222
|
-
throw err;
|
|
223
259
|
}
|
|
224
|
-
|
|
260
|
+
catch (err) {
|
|
261
|
+
if (err instanceof QverisApiError) {
|
|
262
|
+
throw err;
|
|
263
|
+
}
|
|
264
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
265
|
+
throw new QverisApiError({
|
|
266
|
+
status: 408,
|
|
267
|
+
message: 'Request timed out. Check connectivity or increase timeout.',
|
|
268
|
+
observability: withErrorContext(requestContext, 'timeout', 0),
|
|
269
|
+
...(errorCause(err) && { cause: errorCause(err) }),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
225
272
|
throw new QverisApiError({
|
|
226
|
-
status:
|
|
227
|
-
message:
|
|
228
|
-
observability: withErrorContext(requestContext, '
|
|
273
|
+
status: 0,
|
|
274
|
+
message: err instanceof Error && err.message ? err.message : 'Network request failed',
|
|
275
|
+
observability: withErrorContext(requestContext, 'network_error', 0),
|
|
229
276
|
...(errorCause(err) && { cause: errorCause(err) }),
|
|
230
277
|
});
|
|
231
278
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
finally {
|
|
240
|
-
clearTimeout(timeout);
|
|
279
|
+
finally {
|
|
280
|
+
clearTimeout(timeout);
|
|
281
|
+
}
|
|
282
|
+
// Only reached on the retry path (success returns, errors throw above).
|
|
283
|
+
await this.sleep(retryDelayMs ?? 0);
|
|
241
284
|
}
|
|
242
285
|
}
|
|
243
286
|
/**
|
|
@@ -275,10 +318,7 @@ function withErrorContext(context, errorType, httpStatus, requestId) {
|
|
|
275
318
|
}
|
|
276
319
|
function extractRequestId(response) {
|
|
277
320
|
const headers = response.headers;
|
|
278
|
-
return (headers?.get('x-request-id') ??
|
|
279
|
-
headers?.get('x-qveris-request-id') ??
|
|
280
|
-
headers?.get('x-correlation-id') ??
|
|
281
|
-
undefined);
|
|
321
|
+
return (headers?.get('x-request-id') ?? headers?.get('x-qveris-request-id') ?? headers?.get('x-correlation-id') ?? undefined);
|
|
282
322
|
}
|
|
283
323
|
function errorCause(error) {
|
|
284
324
|
if (!(error instanceof Error))
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|