@zerobase-labs/passport-sdk 0.1.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/README.md +147 -0
- package/dist/index.cjs +428 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +294 -0
- package/dist/index.d.ts +294 -0
- package/dist/index.mjs +395 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# @zerobase-labs/passport-sdk
|
|
2
|
+
|
|
3
|
+
> SDK for **Agent Passport** — OAuth-like identity verification for AI agents.
|
|
4
|
+
|
|
5
|
+
Verify agent identities in 3 lines. Authenticate agents in 5.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @zerobase-labs/passport-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm add @zerobase-labs/passport-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add @zerobase-labs/passport-sdk
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start — For Apps (Verify Agents)
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { AgentPassportClient } from '@zerobase-labs/passport-sdk';
|
|
25
|
+
|
|
26
|
+
const passport = new AgentPassportClient({
|
|
27
|
+
baseUrl: 'https://passport-api.onrender.com',
|
|
28
|
+
appId: 'your-app-id',
|
|
29
|
+
appKey: 'ap_live_...',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const result = await passport.verify(agentToken);
|
|
33
|
+
if (result.valid && result.risk?.recommendedAction === 'allow') {
|
|
34
|
+
console.log(`Verified agent: ${result.handle}`);
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Quick Start — For Agents (Authenticate)
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { AgentClient } from '@zerobase-labs/passport-sdk';
|
|
42
|
+
|
|
43
|
+
const agent = new AgentClient({
|
|
44
|
+
baseUrl: 'https://passport-api.onrender.com',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Register once
|
|
48
|
+
const { agentId } = await agent.register({
|
|
49
|
+
handle: 'my-agent',
|
|
50
|
+
publicKeyB64: '<your-ed25519-public-key-base64>',
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Authenticate (challenge → sign → token)
|
|
54
|
+
const { token, expiresAt } = await agent.authenticate({
|
|
55
|
+
agentId,
|
|
56
|
+
sign: async (nonce) => {
|
|
57
|
+
// Sign with YOUR private key — it never enters the SDK
|
|
58
|
+
return signWithEd25519(nonce, privateKey);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Security**: Private keys never enter this SDK. The `sign` callback keeps signing in your code.
|
|
64
|
+
|
|
65
|
+
## API Reference
|
|
66
|
+
|
|
67
|
+
### `AgentPassportClient` (for apps)
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
new AgentPassportClient({
|
|
71
|
+
baseUrl: string; // Agent Passport API URL
|
|
72
|
+
appId: string; // Your App ID (from portal)
|
|
73
|
+
appKey: string; // Your API key (ap_live_...)
|
|
74
|
+
timeoutMs?: number; // Request timeout (default: 10000)
|
|
75
|
+
maxRetries?: number; // Max retries on 429 (default: 3)
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
| Method | Description |
|
|
80
|
+
|--------|-------------|
|
|
81
|
+
| `verify(token)` | Verify an agent's identity token |
|
|
82
|
+
| `introspect(token)` | Introspect a token (RFC 7662) |
|
|
83
|
+
| `revoke(token)` | Revoke a token before expiry |
|
|
84
|
+
|
|
85
|
+
### `AgentClient` (for agents)
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
new AgentClient({
|
|
89
|
+
baseUrl: string; // Agent Passport API URL
|
|
90
|
+
timeoutMs?: number; // Request timeout (default: 10000)
|
|
91
|
+
maxRetries?: number; // Max retries on 429 (default: 3)
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
| Method | Description |
|
|
96
|
+
|--------|-------------|
|
|
97
|
+
| `register({ handle, publicKeyB64 })` | Register a new agent |
|
|
98
|
+
| `authenticate({ agentId, sign })` | Full auth flow (challenge → sign → token) |
|
|
99
|
+
| `getChallenge(agentId)` | Request a challenge nonce |
|
|
100
|
+
| `exchangeToken({ agentId, challengeId, signatureB64 })` | Exchange signature for JWT |
|
|
101
|
+
|
|
102
|
+
## Error Handling
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import {
|
|
106
|
+
PassportError,
|
|
107
|
+
PassportAuthError,
|
|
108
|
+
PassportRateLimitError,
|
|
109
|
+
PassportNetworkError,
|
|
110
|
+
PassportValidationError,
|
|
111
|
+
} from '@zerobase-labs/passport-sdk';
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const result = await passport.verify(token);
|
|
115
|
+
} catch (err) {
|
|
116
|
+
if (err instanceof PassportRateLimitError) {
|
|
117
|
+
console.log(`Rate limited. Retry after ${err.retryAfter}s`);
|
|
118
|
+
} else if (err instanceof PassportAuthError) {
|
|
119
|
+
console.log('Invalid credentials:', err.message);
|
|
120
|
+
} else if (err instanceof PassportNetworkError) {
|
|
121
|
+
console.log('Cannot reach API:', err.message);
|
|
122
|
+
} else if (err instanceof PassportValidationError) {
|
|
123
|
+
console.log('Bad request:', err.message);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The SDK automatically retries 429 responses with exponential backoff (configurable via `maxRetries`).
|
|
129
|
+
|
|
130
|
+
## Compatibility
|
|
131
|
+
|
|
132
|
+
- Node.js 18+
|
|
133
|
+
- Bun
|
|
134
|
+
- Deno
|
|
135
|
+
- Any runtime with `globalThis.fetch`
|
|
136
|
+
|
|
137
|
+
Zero runtime dependencies other than `zod`.
|
|
138
|
+
|
|
139
|
+
## Links
|
|
140
|
+
|
|
141
|
+
- [Main Repository](https://github.com/zerobase-labs/agent-passport)
|
|
142
|
+
- [API Documentation](https://github.com/zerobase-labs/agent-passport/blob/main/docs/openapi.yaml)
|
|
143
|
+
- [Integration Guide](https://github.com/zerobase-labs/agent-passport/blob/main/docs/INTEGRATION.md)
|
|
144
|
+
|
|
145
|
+
## License
|
|
146
|
+
|
|
147
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AgentClient: () => AgentClient,
|
|
24
|
+
AgentPassportClient: () => AgentPassportClient,
|
|
25
|
+
PassportAuthError: () => PassportAuthError,
|
|
26
|
+
PassportError: () => PassportError,
|
|
27
|
+
PassportNetworkError: () => PassportNetworkError,
|
|
28
|
+
PassportRateLimitError: () => PassportRateLimitError,
|
|
29
|
+
PassportValidationError: () => PassportValidationError
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/errors.ts
|
|
34
|
+
var PassportError = class extends Error {
|
|
35
|
+
/** Machine-readable error code (e.g. INVALID_TOKEN, RATE_LIMITED) */
|
|
36
|
+
code;
|
|
37
|
+
/** HTTP status code returned by the API */
|
|
38
|
+
statusCode;
|
|
39
|
+
/** Seconds to wait before retrying (present on 429 responses) */
|
|
40
|
+
retryAfter;
|
|
41
|
+
/** Server-assigned request ID for debugging */
|
|
42
|
+
requestId;
|
|
43
|
+
/** Additional error details from the API */
|
|
44
|
+
details;
|
|
45
|
+
constructor(code, message, statusCode, options) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = "PassportError";
|
|
48
|
+
this.code = code;
|
|
49
|
+
this.statusCode = statusCode;
|
|
50
|
+
this.retryAfter = options?.retryAfter;
|
|
51
|
+
this.requestId = options?.requestId;
|
|
52
|
+
this.details = options?.details;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var PassportNetworkError = class extends PassportError {
|
|
56
|
+
constructor(message, options) {
|
|
57
|
+
super("NETWORK_ERROR", message, 0, {});
|
|
58
|
+
this.name = "PassportNetworkError";
|
|
59
|
+
if (options?.cause) {
|
|
60
|
+
this.cause = options.cause;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
var PassportAuthError = class extends PassportError {
|
|
65
|
+
constructor(code, message, statusCode, options) {
|
|
66
|
+
super(code, message, statusCode, options);
|
|
67
|
+
this.name = "PassportAuthError";
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
var PassportRateLimitError = class extends PassportError {
|
|
71
|
+
constructor(message, retryAfter, options) {
|
|
72
|
+
super("RATE_LIMITED", message, 429, {
|
|
73
|
+
retryAfter,
|
|
74
|
+
requestId: options?.requestId
|
|
75
|
+
});
|
|
76
|
+
this.name = "PassportRateLimitError";
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var PassportValidationError = class extends PassportError {
|
|
80
|
+
constructor(message, options) {
|
|
81
|
+
super("VALIDATION_ERROR", message, 400, options);
|
|
82
|
+
this.name = "PassportValidationError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// src/client.ts
|
|
87
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
88
|
+
var DEFAULT_MAX_RETRIES = 3;
|
|
89
|
+
var BASE_BACKOFF_MS = 1e3;
|
|
90
|
+
var AgentPassportClient = class {
|
|
91
|
+
baseUrl;
|
|
92
|
+
appId;
|
|
93
|
+
appKey;
|
|
94
|
+
timeoutMs;
|
|
95
|
+
maxRetries;
|
|
96
|
+
fetchImpl;
|
|
97
|
+
constructor(options) {
|
|
98
|
+
if (!options.baseUrl) throw new Error("baseUrl is required");
|
|
99
|
+
if (!options.appId) throw new Error("appId is required");
|
|
100
|
+
if (!options.appKey) throw new Error("appKey is required");
|
|
101
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
102
|
+
this.appId = options.appId;
|
|
103
|
+
this.appKey = options.appKey;
|
|
104
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
105
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
106
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
107
|
+
}
|
|
108
|
+
// =========================================================================
|
|
109
|
+
// Public API
|
|
110
|
+
// =========================================================================
|
|
111
|
+
/**
|
|
112
|
+
* Verify an agent's identity token.
|
|
113
|
+
*
|
|
114
|
+
* @param token - The JWT identity token presented by the agent
|
|
115
|
+
* @returns Verification result including agent info and risk assessment
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* const result = await passport.verify(token);
|
|
120
|
+
* if (result.valid) {
|
|
121
|
+
* console.log(`Agent ${result.handle} verified, risk: ${result.risk?.score}`);
|
|
122
|
+
* }
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
async verify(token) {
|
|
126
|
+
const raw = await this.requestWithRetry("POST", "/v1/tokens/verify", {
|
|
127
|
+
token
|
|
128
|
+
});
|
|
129
|
+
if (raw.risk) {
|
|
130
|
+
const ra = raw.risk.recommendedAction ?? raw.risk.action;
|
|
131
|
+
raw.risk.action = ra;
|
|
132
|
+
raw.risk.recommendedAction = ra;
|
|
133
|
+
}
|
|
134
|
+
return raw;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Introspect an agent's identity token (RFC 7662).
|
|
138
|
+
*
|
|
139
|
+
* @param token - The JWT identity token to introspect
|
|
140
|
+
* @returns Token introspection result
|
|
141
|
+
*/
|
|
142
|
+
async introspect(token) {
|
|
143
|
+
return this.requestWithRetry(
|
|
144
|
+
"POST",
|
|
145
|
+
"/v1/tokens/introspect",
|
|
146
|
+
{ token }
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Revoke an agent's identity token before it expires.
|
|
151
|
+
*
|
|
152
|
+
* @param token - The JWT identity token to revoke
|
|
153
|
+
* @returns Revocation result with the token's JTI
|
|
154
|
+
*/
|
|
155
|
+
async revoke(token) {
|
|
156
|
+
return this.requestWithRetry("POST", "/v1/tokens/revoke", {
|
|
157
|
+
token
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// =========================================================================
|
|
161
|
+
// Internal HTTP
|
|
162
|
+
// =========================================================================
|
|
163
|
+
async requestWithRetry(method, path, body) {
|
|
164
|
+
let lastError;
|
|
165
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
166
|
+
try {
|
|
167
|
+
return await this.request(method, path, body);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
lastError = err;
|
|
170
|
+
if (err instanceof PassportRateLimitError && attempt < this.maxRetries) {
|
|
171
|
+
const backoffMs = err.retryAfter ? err.retryAfter * 1e3 : BASE_BACKOFF_MS * Math.pow(2, attempt);
|
|
172
|
+
await sleep(backoffMs);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
throw err;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
throw lastError ?? new Error("Request failed after retries");
|
|
179
|
+
}
|
|
180
|
+
async request(method, path, body) {
|
|
181
|
+
const url = `${this.baseUrl}${path}`;
|
|
182
|
+
const controller = new AbortController();
|
|
183
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
184
|
+
try {
|
|
185
|
+
const response = await this.fetchImpl(url, {
|
|
186
|
+
method,
|
|
187
|
+
headers: {
|
|
188
|
+
"Content-Type": "application/json",
|
|
189
|
+
"X-App-Id": this.appId,
|
|
190
|
+
"X-App-Key": this.appKey
|
|
191
|
+
},
|
|
192
|
+
body: JSON.stringify(body),
|
|
193
|
+
signal: controller.signal
|
|
194
|
+
});
|
|
195
|
+
clearTimeout(timeoutId);
|
|
196
|
+
if (response.ok) {
|
|
197
|
+
return await response.json();
|
|
198
|
+
}
|
|
199
|
+
let errorBody = {};
|
|
200
|
+
try {
|
|
201
|
+
errorBody = await response.json();
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
const code = errorBody.error ?? `HTTP_${response.status}`;
|
|
205
|
+
const message = errorBody.reason ?? errorBody.error ?? response.statusText;
|
|
206
|
+
const requestId = errorBody.request_id;
|
|
207
|
+
if (response.status === 429) {
|
|
208
|
+
const retryAfter = Number(response.headers.get("Retry-After")) || 1;
|
|
209
|
+
throw new PassportRateLimitError(message, retryAfter, { requestId });
|
|
210
|
+
}
|
|
211
|
+
if (response.status === 401 || response.status === 403) {
|
|
212
|
+
throw new PassportAuthError(code, message, response.status, {
|
|
213
|
+
requestId,
|
|
214
|
+
details: errorBody.details
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (response.status === 400) {
|
|
218
|
+
throw new PassportValidationError(message, {
|
|
219
|
+
requestId,
|
|
220
|
+
details: errorBody.details
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
throw new PassportError(code, message, response.status, {
|
|
224
|
+
requestId,
|
|
225
|
+
details: errorBody.details
|
|
226
|
+
});
|
|
227
|
+
} catch (err) {
|
|
228
|
+
clearTimeout(timeoutId);
|
|
229
|
+
if (err instanceof PassportError) {
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
232
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
233
|
+
throw new PassportNetworkError(
|
|
234
|
+
`Request to ${url} timed out after ${this.timeoutMs}ms`,
|
|
235
|
+
{ cause: err }
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
throw new PassportNetworkError(
|
|
239
|
+
`Failed to connect to ${url}: ${err.message}`,
|
|
240
|
+
{ cause: err }
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
function sleep(ms) {
|
|
246
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/agent.ts
|
|
250
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
251
|
+
var DEFAULT_MAX_RETRIES2 = 3;
|
|
252
|
+
var BASE_BACKOFF_MS2 = 1e3;
|
|
253
|
+
var AgentClient = class {
|
|
254
|
+
baseUrl;
|
|
255
|
+
timeoutMs;
|
|
256
|
+
maxRetries;
|
|
257
|
+
fetchImpl;
|
|
258
|
+
constructor(options) {
|
|
259
|
+
if (!options.baseUrl) throw new Error("baseUrl is required");
|
|
260
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
261
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
262
|
+
this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES2;
|
|
263
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
264
|
+
}
|
|
265
|
+
// =========================================================================
|
|
266
|
+
// Public API
|
|
267
|
+
// =========================================================================
|
|
268
|
+
/**
|
|
269
|
+
* Register a new agent with Agent Passport.
|
|
270
|
+
*
|
|
271
|
+
* @param params - Agent handle and Ed25519 public key (base64)
|
|
272
|
+
* @returns Object containing the new agent's ID
|
|
273
|
+
*/
|
|
274
|
+
async register(params) {
|
|
275
|
+
return this.requestWithRetry(
|
|
276
|
+
"POST",
|
|
277
|
+
"/v1/agents/register",
|
|
278
|
+
{
|
|
279
|
+
handle: params.handle,
|
|
280
|
+
publicKeyB64: params.publicKeyB64
|
|
281
|
+
}
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Full authentication flow: request challenge → sign nonce → exchange for token.
|
|
286
|
+
*
|
|
287
|
+
* **SECURITY**: The `sign` callback keeps private keys out of the SDK.
|
|
288
|
+
* You provide the signing logic; the SDK handles the protocol.
|
|
289
|
+
*
|
|
290
|
+
* @param params - Agent ID + async sign callback
|
|
291
|
+
* @returns JWT identity token and its expiration time
|
|
292
|
+
*/
|
|
293
|
+
async authenticate(params) {
|
|
294
|
+
const challenge = await this.getChallenge(params.agentId);
|
|
295
|
+
const signatureB64 = await params.sign(challenge.nonce);
|
|
296
|
+
return this.exchangeToken({
|
|
297
|
+
agentId: params.agentId,
|
|
298
|
+
challengeId: challenge.challengeId,
|
|
299
|
+
signatureB64
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Request a challenge nonce for a specific agent.
|
|
304
|
+
*
|
|
305
|
+
* @param agentId - The agent's UUID
|
|
306
|
+
* @returns Challenge ID, nonce, and expiration time
|
|
307
|
+
*/
|
|
308
|
+
async getChallenge(agentId) {
|
|
309
|
+
return this.requestWithRetry(
|
|
310
|
+
"POST",
|
|
311
|
+
`/v1/agents/${agentId}/challenge`
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Exchange a signed challenge for an identity token.
|
|
316
|
+
*
|
|
317
|
+
* @param params - Agent ID, challenge ID, and base64-encoded signature
|
|
318
|
+
* @returns JWT identity token and its expiration time
|
|
319
|
+
*/
|
|
320
|
+
async exchangeToken(params) {
|
|
321
|
+
return this.requestWithRetry(
|
|
322
|
+
"POST",
|
|
323
|
+
`/v1/agents/${params.agentId}/identity-token`,
|
|
324
|
+
{
|
|
325
|
+
challengeId: params.challengeId,
|
|
326
|
+
signatureB64: params.signatureB64,
|
|
327
|
+
scopes: params.scopes ?? []
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
// =========================================================================
|
|
332
|
+
// Internal HTTP
|
|
333
|
+
// =========================================================================
|
|
334
|
+
async requestWithRetry(method, path, body) {
|
|
335
|
+
let lastError;
|
|
336
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
337
|
+
try {
|
|
338
|
+
return await this.request(method, path, body);
|
|
339
|
+
} catch (err) {
|
|
340
|
+
lastError = err;
|
|
341
|
+
if (err instanceof PassportRateLimitError && attempt < this.maxRetries) {
|
|
342
|
+
const backoffMs = err.retryAfter ? err.retryAfter * 1e3 : BASE_BACKOFF_MS2 * Math.pow(2, attempt);
|
|
343
|
+
await sleep2(backoffMs);
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
throw err;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
throw lastError ?? new Error("Request failed after retries");
|
|
350
|
+
}
|
|
351
|
+
async request(method, path, body) {
|
|
352
|
+
const url = `${this.baseUrl}${path}`;
|
|
353
|
+
const controller = new AbortController();
|
|
354
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
355
|
+
try {
|
|
356
|
+
const init = {
|
|
357
|
+
method,
|
|
358
|
+
headers: { "Content-Type": "application/json" },
|
|
359
|
+
signal: controller.signal
|
|
360
|
+
};
|
|
361
|
+
if (body !== void 0) {
|
|
362
|
+
init.body = JSON.stringify(body);
|
|
363
|
+
}
|
|
364
|
+
const response = await this.fetchImpl(url, init);
|
|
365
|
+
clearTimeout(timeoutId);
|
|
366
|
+
if (response.ok) {
|
|
367
|
+
return await response.json();
|
|
368
|
+
}
|
|
369
|
+
let errorBody = {};
|
|
370
|
+
try {
|
|
371
|
+
errorBody = await response.json();
|
|
372
|
+
} catch {
|
|
373
|
+
}
|
|
374
|
+
const code = errorBody.error ?? `HTTP_${response.status}`;
|
|
375
|
+
const message = errorBody.reason ?? errorBody.error ?? response.statusText;
|
|
376
|
+
const requestId = errorBody.request_id;
|
|
377
|
+
if (response.status === 429) {
|
|
378
|
+
const retryAfter = Number(response.headers.get("Retry-After")) || 1;
|
|
379
|
+
throw new PassportRateLimitError(message, retryAfter, { requestId });
|
|
380
|
+
}
|
|
381
|
+
if (response.status === 401 || response.status === 403) {
|
|
382
|
+
throw new PassportAuthError(code, message, response.status, {
|
|
383
|
+
requestId,
|
|
384
|
+
details: errorBody.details
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (response.status === 400) {
|
|
388
|
+
throw new PassportValidationError(message, {
|
|
389
|
+
requestId,
|
|
390
|
+
details: errorBody.details
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
throw new PassportError(code, message, response.status, {
|
|
394
|
+
requestId,
|
|
395
|
+
details: errorBody.details
|
|
396
|
+
});
|
|
397
|
+
} catch (err) {
|
|
398
|
+
clearTimeout(timeoutId);
|
|
399
|
+
if (err instanceof PassportError) {
|
|
400
|
+
throw err;
|
|
401
|
+
}
|
|
402
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
403
|
+
throw new PassportNetworkError(
|
|
404
|
+
`Request to ${url} timed out after ${this.timeoutMs}ms`,
|
|
405
|
+
{ cause: err }
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
throw new PassportNetworkError(
|
|
409
|
+
`Failed to connect to ${url}: ${err.message}`,
|
|
410
|
+
{ cause: err }
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
function sleep2(ms) {
|
|
416
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
417
|
+
}
|
|
418
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
419
|
+
0 && (module.exports = {
|
|
420
|
+
AgentClient,
|
|
421
|
+
AgentPassportClient,
|
|
422
|
+
PassportAuthError,
|
|
423
|
+
PassportError,
|
|
424
|
+
PassportNetworkError,
|
|
425
|
+
PassportRateLimitError,
|
|
426
|
+
PassportValidationError
|
|
427
|
+
});
|
|
428
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/agent.ts"],"sourcesContent":["// ============================================================================\r\n// Agent Passport SDK — Main entry point\r\n// ============================================================================\r\n\r\n// Clients\r\nexport { AgentPassportClient } from './client.js';\r\nexport { AgentClient } from './agent.js';\r\n\r\n// Error classes\r\nexport {\r\n PassportError,\r\n PassportNetworkError,\r\n PassportAuthError,\r\n PassportRateLimitError,\r\n PassportValidationError,\r\n} from './errors.js';\r\n\r\n// Types\r\nexport type {\r\n AgentPassportClientOptions,\r\n AgentClientOptions,\r\n VerifyResult,\r\n IntrospectResult,\r\n RevokeResult,\r\n RiskAction,\r\n RiskAssessment,\r\n RegisterAgentParams,\r\n RegisterAgentResult,\r\n ChallengeResult,\r\n AuthenticateParams,\r\n AuthenticateResult,\r\n ExchangeTokenParams,\r\n} from './types.js';\r\n","// ============================================================================\r\n// Agent Passport SDK — Error Classes\r\n// ============================================================================\r\n\r\n/**\r\n * Base error class for all Agent Passport SDK errors.\r\n * Extends the native Error with HTTP status code and structured error info.\r\n */\r\nexport class PassportError extends Error {\r\n /** Machine-readable error code (e.g. INVALID_TOKEN, RATE_LIMITED) */\r\n public readonly code: string;\r\n /** HTTP status code returned by the API */\r\n public readonly statusCode: number;\r\n /** Seconds to wait before retrying (present on 429 responses) */\r\n public readonly retryAfter?: number;\r\n /** Server-assigned request ID for debugging */\r\n public readonly requestId?: string;\r\n /** Additional error details from the API */\r\n public readonly details?: Record<string, unknown>;\r\n\r\n constructor(\r\n code: string,\r\n message: string,\r\n statusCode: number,\r\n options?: {\r\n retryAfter?: number;\r\n requestId?: string;\r\n details?: Record<string, unknown>;\r\n },\r\n ) {\r\n super(message);\r\n this.name = 'PassportError';\r\n this.code = code;\r\n this.statusCode = statusCode;\r\n this.retryAfter = options?.retryAfter;\r\n this.requestId = options?.requestId;\r\n this.details = options?.details;\r\n }\r\n}\r\n\r\n/**\r\n * Thrown when the SDK cannot reach the Agent Passport API\r\n * (DNS failure, connection refused, timeout, etc.)\r\n */\r\nexport class PassportNetworkError extends PassportError {\r\n constructor(message: string, options?: { cause?: Error }) {\r\n super('NETWORK_ERROR', message, 0, {});\r\n this.name = 'PassportNetworkError';\r\n if (options?.cause) {\r\n this.cause = options.cause;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Thrown on 401 or 403 responses — invalid or missing credentials.\r\n */\r\nexport class PassportAuthError extends PassportError {\r\n constructor(\r\n code: string,\r\n message: string,\r\n statusCode: number,\r\n options?: { requestId?: string; details?: Record<string, unknown> },\r\n ) {\r\n super(code, message, statusCode, options);\r\n this.name = 'PassportAuthError';\r\n }\r\n}\r\n\r\n/**\r\n * Thrown on 429 responses — too many requests.\r\n * Check `retryAfter` for the number of seconds to wait.\r\n */\r\nexport class PassportRateLimitError extends PassportError {\r\n constructor(\r\n message: string,\r\n retryAfter: number,\r\n options?: { requestId?: string },\r\n ) {\r\n super('RATE_LIMITED', message, 429, {\r\n retryAfter,\r\n requestId: options?.requestId,\r\n });\r\n this.name = 'PassportRateLimitError';\r\n }\r\n}\r\n\r\n/**\r\n * Thrown on 400 responses — request validation failed.\r\n */\r\nexport class PassportValidationError extends PassportError {\r\n constructor(\r\n message: string,\r\n options?: {\r\n requestId?: string;\r\n details?: Record<string, unknown>;\r\n },\r\n ) {\r\n super('VALIDATION_ERROR', message, 400, options);\r\n this.name = 'PassportValidationError';\r\n }\r\n}\r\n","// ============================================================================\r\n// Agent Passport SDK — AgentPassportClient (for apps verifying agents)\r\n// ============================================================================\r\n\r\nimport {\r\n PassportError,\r\n PassportNetworkError,\r\n PassportAuthError,\r\n PassportRateLimitError,\r\n PassportValidationError,\r\n} from './errors.js';\r\nimport type {\r\n AgentPassportClientOptions,\r\n VerifyResult,\r\n IntrospectResult,\r\n RevokeResult,\r\n} from './types.js';\r\n\r\nconst DEFAULT_TIMEOUT_MS = 10_000;\r\nconst DEFAULT_MAX_RETRIES = 3;\r\nconst BASE_BACKOFF_MS = 1_000;\r\n\r\n/**\r\n * Client for **apps** that want to verify agent identity tokens.\r\n *\r\n * @example\r\n * ```ts\r\n * import { AgentPassportClient } from '@zerobase-labs/passport-sdk';\r\n *\r\n * const passport = new AgentPassportClient({\r\n * baseUrl: 'https://passport-api.onrender.com',\r\n * appId: 'your-app-id',\r\n * appKey: 'ap_live_...',\r\n * });\r\n *\r\n * const result = await passport.verify(token);\r\n * if (result.valid && result.risk?.action === 'allow') {\r\n * // Agent is who they say they are ✓\r\n * }\r\n * ```\r\n */\r\nexport class AgentPassportClient {\r\n private readonly baseUrl: string;\r\n private readonly appId: string;\r\n private readonly appKey: string;\r\n private readonly timeoutMs: number;\r\n private readonly maxRetries: number;\r\n private readonly fetchImpl: typeof globalThis.fetch;\r\n\r\n constructor(options: AgentPassportClientOptions) {\r\n if (!options.baseUrl) throw new Error('baseUrl is required');\r\n if (!options.appId) throw new Error('appId is required');\r\n if (!options.appKey) throw new Error('appKey is required');\r\n\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.appId = options.appId;\r\n this.appKey = options.appKey;\r\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\r\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\r\n this.fetchImpl = options.fetch ?? globalThis.fetch;\r\n }\r\n\r\n // =========================================================================\r\n // Public API\r\n // =========================================================================\r\n\r\n /**\r\n * Verify an agent's identity token.\r\n *\r\n * @param token - The JWT identity token presented by the agent\r\n * @returns Verification result including agent info and risk assessment\r\n *\r\n * @example\r\n * ```ts\r\n * const result = await passport.verify(token);\r\n * if (result.valid) {\r\n * console.log(`Agent ${result.handle} verified, risk: ${result.risk?.score}`);\r\n * }\r\n * ```\r\n */\r\n async verify(token: string): Promise<VerifyResult> {\r\n const raw = await this.requestWithRetry<VerifyResult>('POST', '/v1/tokens/verify', {\r\n token,\r\n });\r\n\r\n // The API returns `recommendedAction`; also expose it as `action` for convenience\r\n if (raw.risk) {\r\n const ra = raw.risk.recommendedAction ?? raw.risk.action;\r\n (raw.risk as { action: string; recommendedAction: string }).action = ra;\r\n (raw.risk as { action: string; recommendedAction: string }).recommendedAction = ra;\r\n }\r\n\r\n return raw;\r\n }\r\n\r\n /**\r\n * Introspect an agent's identity token (RFC 7662).\r\n *\r\n * @param token - The JWT identity token to introspect\r\n * @returns Token introspection result\r\n */\r\n async introspect(token: string): Promise<IntrospectResult> {\r\n return this.requestWithRetry<IntrospectResult>(\r\n 'POST',\r\n '/v1/tokens/introspect',\r\n { token },\r\n );\r\n }\r\n\r\n /**\r\n * Revoke an agent's identity token before it expires.\r\n *\r\n * @param token - The JWT identity token to revoke\r\n * @returns Revocation result with the token's JTI\r\n */\r\n async revoke(token: string): Promise<RevokeResult> {\r\n return this.requestWithRetry<RevokeResult>('POST', '/v1/tokens/revoke', {\r\n token,\r\n });\r\n }\r\n\r\n // =========================================================================\r\n // Internal HTTP\r\n // =========================================================================\r\n\r\n private async requestWithRetry<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n ): Promise<T> {\r\n let lastError: Error | undefined;\r\n\r\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\r\n try {\r\n return await this.request<T>(method, path, body);\r\n } catch (err) {\r\n lastError = err as Error;\r\n\r\n // Only retry on 429 (rate limit) responses\r\n if (err instanceof PassportRateLimitError && attempt < this.maxRetries) {\r\n const backoffMs = err.retryAfter\r\n ? err.retryAfter * 1_000\r\n : BASE_BACKOFF_MS * Math.pow(2, attempt);\r\n await sleep(backoffMs);\r\n continue;\r\n }\r\n\r\n throw err;\r\n }\r\n }\r\n\r\n // Should not reach here, but just in case\r\n throw lastError ?? new Error('Request failed after retries');\r\n }\r\n\r\n private async request<T>(\r\n method: string,\r\n path: string,\r\n body: unknown,\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${path}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\r\n\r\n try {\r\n const response = await this.fetchImpl(url, {\r\n method,\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-App-Id': this.appId,\r\n 'X-App-Key': this.appKey,\r\n },\r\n body: JSON.stringify(body),\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (response.ok) {\r\n return (await response.json()) as T;\r\n }\r\n\r\n // Parse error body\r\n let errorBody: { error?: string; reason?: string; details?: Record<string, unknown>; request_id?: string } = {};\r\n try {\r\n errorBody = (await response.json()) as typeof errorBody;\r\n } catch {\r\n // Non-JSON error response — use status text\r\n }\r\n\r\n const code = errorBody.error ?? `HTTP_${response.status}`;\r\n const message = errorBody.reason ?? errorBody.error ?? response.statusText;\r\n const requestId = errorBody.request_id;\r\n\r\n if (response.status === 429) {\r\n const retryAfter = Number(response.headers.get('Retry-After')) || 1;\r\n throw new PassportRateLimitError(message, retryAfter, { requestId });\r\n }\r\n\r\n if (response.status === 401 || response.status === 403) {\r\n throw new PassportAuthError(code, message, response.status, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n }\r\n\r\n if (response.status === 400) {\r\n throw new PassportValidationError(message, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n }\r\n\r\n throw new PassportError(code, message, response.status, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n } catch (err) {\r\n clearTimeout(timeoutId);\r\n\r\n // Re-throw SDK errors as-is\r\n if (err instanceof PassportError) {\r\n throw err;\r\n }\r\n\r\n // Wrap native errors\r\n if (err instanceof DOMException && err.name === 'AbortError') {\r\n throw new PassportNetworkError(\r\n `Request to ${url} timed out after ${this.timeoutMs}ms`,\r\n { cause: err },\r\n );\r\n }\r\n\r\n throw new PassportNetworkError(\r\n `Failed to connect to ${url}: ${(err as Error).message}`,\r\n { cause: err as Error },\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n","// ============================================================================\r\n// Agent Passport SDK — AgentClient (for agents authenticating themselves)\r\n// ============================================================================\r\n\r\nimport {\r\n PassportError,\r\n PassportNetworkError,\r\n PassportRateLimitError,\r\n PassportValidationError,\r\n PassportAuthError,\r\n} from './errors.js';\r\nimport type {\r\n AgentClientOptions,\r\n RegisterAgentParams,\r\n RegisterAgentResult,\r\n ChallengeResult,\r\n AuthenticateParams,\r\n AuthenticateResult,\r\n ExchangeTokenParams,\r\n} from './types.js';\r\n\r\nconst DEFAULT_TIMEOUT_MS = 10_000;\r\nconst DEFAULT_MAX_RETRIES = 3;\r\nconst BASE_BACKOFF_MS = 1_000;\r\n\r\n/**\r\n * Client for **AI agents** that want to authenticate with Agent Passport.\r\n *\r\n * **SECURITY**: Private keys never enter this SDK. The `authenticate()` method\r\n * takes a `sign` callback — your code does the signing and only the signature\r\n * is sent to the API.\r\n *\r\n * @example\r\n * ```ts\r\n * import { AgentClient } from '@zerobase-labs/passport-sdk';\r\n *\r\n * const agent = new AgentClient({\r\n * baseUrl: 'https://passport-api.onrender.com',\r\n * });\r\n *\r\n * // Register a new agent\r\n * const { agentId } = await agent.register({\r\n * handle: 'my-cool-agent',\r\n * publicKeyB64: '...',\r\n * });\r\n *\r\n * // Authenticate (challenge → sign → token)\r\n * const { token, expiresAt } = await agent.authenticate({\r\n * agentId,\r\n * sign: async (nonce) => {\r\n * // Sign with your private key — it never leaves your code\r\n * return mySignFunction(nonce, privateKey);\r\n * },\r\n * });\r\n * ```\r\n */\r\nexport class AgentClient {\r\n private readonly baseUrl: string;\r\n private readonly timeoutMs: number;\r\n private readonly maxRetries: number;\r\n private readonly fetchImpl: typeof globalThis.fetch;\r\n\r\n constructor(options: AgentClientOptions) {\r\n if (!options.baseUrl) throw new Error('baseUrl is required');\r\n\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\r\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\r\n this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;\r\n this.fetchImpl = options.fetch ?? globalThis.fetch;\r\n }\r\n\r\n // =========================================================================\r\n // Public API\r\n // =========================================================================\r\n\r\n /**\r\n * Register a new agent with Agent Passport.\r\n *\r\n * @param params - Agent handle and Ed25519 public key (base64)\r\n * @returns Object containing the new agent's ID\r\n */\r\n async register(params: RegisterAgentParams): Promise<RegisterAgentResult> {\r\n return this.requestWithRetry<RegisterAgentResult>(\r\n 'POST',\r\n '/v1/agents/register',\r\n {\r\n handle: params.handle,\r\n publicKeyB64: params.publicKeyB64,\r\n },\r\n );\r\n }\r\n\r\n /**\r\n * Full authentication flow: request challenge → sign nonce → exchange for token.\r\n *\r\n * **SECURITY**: The `sign` callback keeps private keys out of the SDK.\r\n * You provide the signing logic; the SDK handles the protocol.\r\n *\r\n * @param params - Agent ID + async sign callback\r\n * @returns JWT identity token and its expiration time\r\n */\r\n async authenticate(params: AuthenticateParams): Promise<AuthenticateResult> {\r\n // Step 1: Request challenge\r\n const challenge = await this.getChallenge(params.agentId);\r\n\r\n // Step 2: Sign the nonce with the user-provided callback\r\n const signatureB64 = await params.sign(challenge.nonce);\r\n\r\n // Step 3: Exchange signature for token\r\n return this.exchangeToken({\r\n agentId: params.agentId,\r\n challengeId: challenge.challengeId,\r\n signatureB64,\r\n });\r\n }\r\n\r\n /**\r\n * Request a challenge nonce for a specific agent.\r\n *\r\n * @param agentId - The agent's UUID\r\n * @returns Challenge ID, nonce, and expiration time\r\n */\r\n async getChallenge(agentId: string): Promise<ChallengeResult> {\r\n return this.requestWithRetry<ChallengeResult>(\r\n 'POST',\r\n `/v1/agents/${agentId}/challenge`,\r\n );\r\n }\r\n\r\n /**\r\n * Exchange a signed challenge for an identity token.\r\n *\r\n * @param params - Agent ID, challenge ID, and base64-encoded signature\r\n * @returns JWT identity token and its expiration time\r\n */\r\n async exchangeToken(params: ExchangeTokenParams): Promise<AuthenticateResult> {\r\n return this.requestWithRetry<AuthenticateResult>(\r\n 'POST',\r\n `/v1/agents/${params.agentId}/identity-token`,\r\n {\r\n challengeId: params.challengeId,\r\n signatureB64: params.signatureB64,\r\n scopes: params.scopes ?? [],\r\n },\r\n );\r\n }\r\n\r\n // =========================================================================\r\n // Internal HTTP\r\n // =========================================================================\r\n\r\n private async requestWithRetry<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n ): Promise<T> {\r\n let lastError: Error | undefined;\r\n\r\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\r\n try {\r\n return await this.request<T>(method, path, body);\r\n } catch (err) {\r\n lastError = err as Error;\r\n\r\n if (err instanceof PassportRateLimitError && attempt < this.maxRetries) {\r\n const backoffMs = err.retryAfter\r\n ? err.retryAfter * 1_000\r\n : BASE_BACKOFF_MS * Math.pow(2, attempt);\r\n await sleep(backoffMs);\r\n continue;\r\n }\r\n\r\n throw err;\r\n }\r\n }\r\n\r\n throw lastError ?? new Error('Request failed after retries');\r\n }\r\n\r\n private async request<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n ): Promise<T> {\r\n const url = `${this.baseUrl}${path}`;\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\r\n\r\n try {\r\n const init: RequestInit = {\r\n method,\r\n headers: { 'Content-Type': 'application/json' },\r\n signal: controller.signal,\r\n };\r\n\r\n if (body !== undefined) {\r\n init.body = JSON.stringify(body);\r\n }\r\n\r\n const response = await this.fetchImpl(url, init);\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (response.ok) {\r\n return (await response.json()) as T;\r\n }\r\n\r\n let errorBody: {\r\n error?: string;\r\n reason?: string;\r\n details?: Record<string, unknown>;\r\n request_id?: string;\r\n } = {};\r\n try {\r\n errorBody = (await response.json()) as typeof errorBody;\r\n } catch {\r\n // Non-JSON response\r\n }\r\n\r\n const code = errorBody.error ?? `HTTP_${response.status}`;\r\n const message = errorBody.reason ?? errorBody.error ?? response.statusText;\r\n const requestId = errorBody.request_id;\r\n\r\n if (response.status === 429) {\r\n const retryAfter = Number(response.headers.get('Retry-After')) || 1;\r\n throw new PassportRateLimitError(message, retryAfter, { requestId });\r\n }\r\n\r\n if (response.status === 401 || response.status === 403) {\r\n throw new PassportAuthError(code, message, response.status, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n }\r\n\r\n if (response.status === 400) {\r\n throw new PassportValidationError(message, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n }\r\n\r\n throw new PassportError(code, message, response.status, {\r\n requestId,\r\n details: errorBody.details,\r\n });\r\n } catch (err) {\r\n clearTimeout(timeoutId);\r\n\r\n if (err instanceof PassportError) {\r\n throw err;\r\n }\r\n\r\n if (err instanceof DOMException && err.name === 'AbortError') {\r\n throw new PassportNetworkError(\r\n `Request to ${url} timed out after ${this.timeoutMs}ms`,\r\n { cause: err },\r\n );\r\n }\r\n\r\n throw new PassportNetworkError(\r\n `Failed to connect to ${url}: ${(err as Error).message}`,\r\n { cause: err as Error },\r\n );\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Helpers\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n"],"mappings":"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","names":["DEFAULT_TIMEOUT_MS","DEFAULT_MAX_RETRIES","BASE_BACKOFF_MS","sleep"]}
|