@bind-protocol/sdk 0.8.0 → 0.10.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.
Files changed (40) hide show
  1. package/README.md +7 -11
  2. package/dist/{adapter-DBvPax2O.d.cts → adapter-BRj4bkLl.d.ts} +22 -8
  3. package/dist/{adapter-LeDOUfnn.d.ts → adapter-CNeHM6SQ.d.cts} +22 -8
  4. package/dist/adapters/dimo/index.cjs +26 -10
  5. package/dist/adapters/dimo/index.cjs.map +1 -1
  6. package/dist/adapters/dimo/index.d.cts +9 -3
  7. package/dist/adapters/dimo/index.d.ts +9 -3
  8. package/dist/adapters/dimo/index.js +26 -10
  9. package/dist/adapters/dimo/index.js.map +1 -1
  10. package/dist/adapters/index.cjs +139 -148
  11. package/dist/adapters/index.cjs.map +1 -1
  12. package/dist/adapters/index.d.cts +4 -4
  13. package/dist/adapters/index.d.ts +4 -4
  14. package/dist/adapters/index.js +139 -148
  15. package/dist/adapters/index.js.map +1 -1
  16. package/dist/adapters/zktls/index.cjs +113 -138
  17. package/dist/adapters/zktls/index.cjs.map +1 -1
  18. package/dist/adapters/zktls/index.d.cts +3 -3
  19. package/dist/adapters/zktls/index.d.ts +3 -3
  20. package/dist/adapters/zktls/index.js +113 -138
  21. package/dist/adapters/zktls/index.js.map +1 -1
  22. package/dist/{client-Dlp02kxb.d.cts → client-CfYXpFLk.d.cts} +70 -32
  23. package/dist/{client-BsloIjSG.d.ts → client-CpJ87Xe0.d.ts} +70 -32
  24. package/dist/core/index.cjs +107 -125
  25. package/dist/core/index.cjs.map +1 -1
  26. package/dist/core/index.d.cts +2 -2
  27. package/dist/core/index.d.ts +2 -2
  28. package/dist/core/index.js +107 -125
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/index.cjs +139 -148
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +4 -4
  33. package/dist/index.d.ts +4 -4
  34. package/dist/index.js +139 -148
  35. package/dist/index.js.map +1 -1
  36. package/dist/{types-D5XJykY-.d.cts → types-BcPssdQk.d.cts} +30 -174
  37. package/dist/{types-D5XJykY-.d.ts → types-BcPssdQk.d.ts} +30 -174
  38. package/dist/{types-CXWgNPXN.d.ts → types-D7Q7ymPa.d.ts} +1 -1
  39. package/dist/{types-D-cTYE3o.d.cts → types-ywkMNwun.d.cts} +1 -1
  40. package/package.json +1 -1
@@ -7,12 +7,9 @@ function buildTelemetryQuery(vehicleTokenId, from, to) {
7
7
  from: ${from},
8
8
  to: ${to}
9
9
  ) {
10
- powertrainTransmissionTravelledDistance(agg: AVG)
11
- speed(agg: AVG)
12
- powertrainCombustionEngineSpeed(agg: AVG)
13
- obdEngineLoad(agg: AVG)
14
- obdDTCList(agg: UNIQUE)
15
- obdRunTime(agg: AVG)
10
+ powertrainTransmissionTravelledDistance(agg: SUM)
11
+ isIgnitionOn(agg: COUNT)
12
+ speed(agg: MAX)
16
13
  timestamp
17
14
  }
18
15
  }`;
@@ -20,7 +17,7 @@ function buildTelemetryQuery(vehicleTokenId, from, to) {
20
17
 
21
18
  // src/adapters/dimo/adapter.ts
22
19
  var SUPPORTED_CIRCUITS = [
23
- "bind.mobility.riskband.v1"
20
+ "bind.dimo.riskband.v0_1_0"
24
21
  ];
25
22
  var DimoAdapter = class {
26
23
  id = "dimo";
@@ -53,7 +50,7 @@ var DimoAdapter = class {
53
50
  );
54
51
  }
55
52
  switch (circuitId) {
56
- case "bind.mobility.riskband.v1":
53
+ case "bind.dimo.riskband.v0_1_0":
57
54
  return this.toRiskBandInputs(data);
58
55
  default:
59
56
  throw new Error(`No input transformer for circuit: ${circuitId}`);
@@ -68,10 +65,29 @@ var DimoAdapter = class {
68
65
  // ===========================================================================
69
66
  // Private transformers
70
67
  // ===========================================================================
68
+ /**
69
+ * Aggregate hourly telemetry rows into the three circuit inputs
70
+ * required by bind.mobility.basicriskband:
71
+ *
72
+ * mileage_90d (u32) — SUM of powertrainTransmissionTravelledDistance
73
+ * data_points (u32) — COUNT of isIgnitionOn (sum of per-hour counts)
74
+ * speed_max (u16) — MAX of speed
75
+ */
71
76
  toRiskBandInputs(data) {
77
+ let mileageSum = 0;
78
+ let dataPointsSum = 0;
79
+ let speedMax = 0;
80
+ for (const row of data.signals) {
81
+ mileageSum += row.powertrainTransmissionTravelledDistance ?? 0;
82
+ dataPointsSum += row.isIgnitionOn ?? 0;
83
+ if ((row.speed ?? 0) > speedMax) {
84
+ speedMax = row.speed;
85
+ }
86
+ }
72
87
  return {
73
- signals: JSON.stringify(data.signals),
74
- timestamp: data.timestamp
88
+ mileage_90d: String(Math.round(mileageSum)),
89
+ data_points: String(Math.round(dataPointsSum)),
90
+ speed_max: String(Math.round(speedMax))
75
91
  };
76
92
  }
77
93
  };
@@ -163,33 +179,42 @@ var BindClient = class {
163
179
  * @throws {InsufficientCreditsError} If there aren't enough credits
164
180
  */
165
181
  async submitProveJob(circuitId, inputs, options) {
166
- const response = await this.fetch("/api/prove", {
167
- method: "POST",
168
- body: JSON.stringify({
169
- circuitId,
170
- inputs,
171
- verificationMode: options?.verificationMode
172
- })
173
- });
174
- const result = await response.json();
175
- if (!result.success && result.requiredCredits !== void 0 && result.availableCredits !== void 0) {
176
- throw new InsufficientCreditsError(result.requiredCredits, result.availableCredits);
182
+ try {
183
+ return await this.fetchJson("/api/prove", {
184
+ method: "POST",
185
+ body: JSON.stringify({
186
+ circuitId,
187
+ inputs,
188
+ verificationMode: options?.verificationMode
189
+ })
190
+ });
191
+ } catch (err) {
192
+ if (err instanceof ApiError && err.response) {
193
+ const body = err.response;
194
+ if (body.requiredCredits !== void 0 && body.availableCredits !== void 0) {
195
+ throw new InsufficientCreditsError(
196
+ body.requiredCredits,
197
+ body.availableCredits
198
+ );
199
+ }
200
+ }
201
+ throw err;
177
202
  }
178
- return result;
179
203
  }
180
204
  /**
181
205
  * Get the status and results of a prove job
182
206
  * @param jobId - The unique job identifier
183
207
  * @returns The job details including status and outputs
208
+ * @throws {ApiError} If the API request fails
184
209
  */
185
210
  async getProveJob(jobId) {
186
- const response = await this.fetch(`/api/prove/${encodeURIComponent(jobId)}`);
187
- return response.json();
211
+ return this.fetchJson(`/api/prove/${encodeURIComponent(jobId)}`);
188
212
  }
189
213
  /**
190
214
  * List prove jobs for the authenticated organization
191
215
  * @param options - Optional filters for status, limit, and offset
192
216
  * @returns Paginated list of prove jobs
217
+ * @throws {ApiError} If the API request fails
193
218
  */
194
219
  async listProveJobs(options = {}) {
195
220
  const params = new URLSearchParams();
@@ -198,8 +223,7 @@ var BindClient = class {
198
223
  if (options.offset !== void 0) params.set("offset", options.offset.toString());
199
224
  const queryString = params.toString();
200
225
  const path = queryString ? `/api/prove?${queryString}` : "/api/prove";
201
- const response = await this.fetch(path);
202
- return response.json();
226
+ return this.fetchJson(path);
203
227
  }
204
228
  /**
205
229
  * Poll for prove job completion
@@ -207,21 +231,14 @@ var BindClient = class {
207
231
  * @param options - Polling options
208
232
  * @returns The completed or failed job
209
233
  * @throws {TimeoutError} If the job doesn't complete within the timeout
234
+ * @throws {ApiError} If the API request fails
210
235
  */
211
236
  async waitForProveJob(jobId, options = {}) {
212
237
  const intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
213
238
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
214
239
  const startTime = Date.now();
215
240
  while (Date.now() - startTime < timeoutMs) {
216
- const result = await this.getProveJob(jobId);
217
- if (!result.success || !result.data) {
218
- throw new ApiError(
219
- result.error || "Failed to get prove job",
220
- 500,
221
- result
222
- );
223
- }
224
- const job = result.data;
241
+ const job = await this.getProveJob(jobId);
225
242
  if (options.onProgress) {
226
243
  options.onProgress(job);
227
244
  }
@@ -241,41 +258,28 @@ var BindClient = class {
241
258
  /**
242
259
  * List all available public policies
243
260
  * @returns Array of public policy specifications
261
+ * @throws {ApiError} If the API request fails
244
262
  */
245
263
  async listPolicies() {
246
- const response = await fetch(`${this.baseUrl}/api/policies`, {
247
- method: "GET"
248
- });
249
- if (!response.ok) {
250
- throw new ApiError(
251
- `Failed to fetch policies: ${response.statusText}`,
252
- response.status
253
- );
254
- }
255
- const json = await response.json();
256
- return json.data ?? json;
264
+ return this.fetchJson("/api/policies");
257
265
  }
258
266
  /**
259
267
  * Get a specific policy by ID
260
268
  * @param policyId - The unique policy identifier
261
269
  * @returns The public policy specification, or null if not found
270
+ * @throws {ApiError} If the API request fails (except 404)
262
271
  */
263
272
  async getPolicy(policyId) {
264
- const response = await fetch(
265
- `${this.baseUrl}/api/policies/${encodeURIComponent(policyId)}`,
266
- { method: "GET" }
267
- );
268
- if (response.status === 404) {
269
- return null;
270
- }
271
- if (!response.ok) {
272
- throw new ApiError(
273
- `Failed to fetch policy: ${response.statusText}`,
274
- response.status
273
+ try {
274
+ return await this.fetchJson(
275
+ `/api/policies/${encodeURIComponent(policyId)}`
275
276
  );
277
+ } catch (err) {
278
+ if (err instanceof ApiError && err.status === 404) {
279
+ return null;
280
+ }
281
+ throw err;
276
282
  }
277
- const json = await response.json();
278
- return json.data ?? json;
279
283
  }
280
284
  // ==========================================================================
281
285
  // zkTLS Methods
@@ -283,49 +287,49 @@ var BindClient = class {
283
287
  /**
284
288
  * List available zkTLS extractors (data sources)
285
289
  * @returns Array of available extractors
290
+ * @throws {ApiError} If the API request fails
286
291
  */
287
292
  async listExtractors() {
288
- const response = await this.fetch("/api/zktls/extractors");
289
- return response.json();
293
+ return this.fetchJson("/api/zktls/extractors");
290
294
  }
291
295
  /**
292
296
  * List zkTLS attestations for the authenticated organization
293
297
  * @returns Array of attestations
298
+ * @throws {ApiError} If the API request fails
294
299
  */
295
300
  async listAttestations() {
296
- const response = await this.fetch("/api/zktls/attestations");
297
- return response.json();
301
+ return this.fetchJson("/api/zktls/attestations");
298
302
  }
299
303
  /**
300
304
  * Get a specific attestation by ID
301
305
  * @param attestationId - The attestation UUID
302
- * @returns The attestation or null if not found
306
+ * @returns The attestation details
307
+ * @throws {ApiError} If the API request fails
303
308
  */
304
309
  async getAttestation(attestationId) {
305
- const response = await this.fetch(`/api/zktls/attestations/${encodeURIComponent(attestationId)}`);
306
- return response.json();
310
+ return this.fetchJson(`/api/zktls/attestations/${encodeURIComponent(attestationId)}`);
307
311
  }
308
312
  /**
309
313
  * Create a new zkTLS session for data attestation
310
314
  * @param extractorId - The extractor to use (e.g., "coinbase")
311
315
  * @param callbackUrl - URL to redirect to after authentication
312
316
  * @returns Session ID and auth URL to redirect user to
317
+ * @throws {ApiError} If the API request fails
313
318
  */
314
319
  async createZkTlsSession(extractorId, callbackUrl) {
315
- const response = await this.fetch("/api/zktls/sessions", {
320
+ return this.fetchJson("/api/zktls/sessions", {
316
321
  method: "POST",
317
322
  body: JSON.stringify({ extractor: extractorId, callbackUrl })
318
323
  });
319
- return response.json();
320
324
  }
321
325
  /**
322
326
  * Get the status of a zkTLS session
323
327
  * @param sessionId - The session UUID
324
328
  * @returns Session status and attestation if completed
329
+ * @throws {ApiError} If the API request fails
325
330
  */
326
331
  async getZkTlsSession(sessionId) {
327
- const response = await this.fetch(`/api/zktls/sessions/${encodeURIComponent(sessionId)}`);
328
- return response.json();
332
+ return this.fetchJson(`/api/zktls/sessions/${encodeURIComponent(sessionId)}`);
329
333
  }
330
334
  /**
331
335
  * Wait for a zkTLS session to complete
@@ -335,21 +339,14 @@ var BindClient = class {
335
339
  * @throws {ZkTlsSessionExpiredError} If session expires
336
340
  * @throws {ZkTlsSessionFailedError} If session fails
337
341
  * @throws {TimeoutError} If timeout is reached
342
+ * @throws {ApiError} If the API request fails
338
343
  */
339
344
  async waitForZkTlsSession(sessionId, options = {}) {
340
345
  const intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
341
346
  const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
342
347
  const startTime = Date.now();
343
348
  while (Date.now() - startTime < timeoutMs) {
344
- const result = await this.getZkTlsSession(sessionId);
345
- if (!result.success || !result.data) {
346
- throw new ApiError(
347
- result.error || "Failed to get zkTLS session",
348
- 500,
349
- result
350
- );
351
- }
352
- const session = result.data;
349
+ const session = await this.getZkTlsSession(sessionId);
353
350
  if (options.onProgress) {
354
351
  options.onProgress(session);
355
352
  }
@@ -376,6 +373,7 @@ var BindClient = class {
376
373
  * List available circuits
377
374
  * @param options - Optional filters
378
375
  * @returns Array of circuits
376
+ * @throws {ApiError} If the API request fails
379
377
  */
380
378
  async listCircuits(options = {}) {
381
379
  const params = new URLSearchParams();
@@ -383,28 +381,27 @@ var BindClient = class {
383
381
  if (options.policyId) params.set("policyId", options.policyId);
384
382
  const queryString = params.toString();
385
383
  const path = queryString ? `/api/circuits?${queryString}` : "/api/circuits";
386
- const response = await this.fetch(path);
387
- return response.json();
384
+ return this.fetchJson(path);
388
385
  }
389
386
  /**
390
387
  * Get a specific circuit by ID
391
388
  * @param circuitId - The circuit identifier
392
- * @returns The circuit details or null if not found
389
+ * @returns The circuit details
390
+ * @throws {ApiError} If the API request fails
393
391
  */
394
392
  async getCircuit(circuitId) {
395
- const response = await this.fetch(`/api/circuits/${encodeURIComponent(circuitId)}`);
396
- return response.json();
393
+ return this.fetchJson(`/api/circuits/${encodeURIComponent(circuitId)}`);
397
394
  }
398
395
  /**
399
396
  * Activate a circuit (requires validation to have passed)
400
397
  * @param circuitId - The circuit identifier to activate
401
398
  * @returns The activation result
399
+ * @throws {ApiError} If the API request fails
402
400
  */
403
401
  async activateCircuit(circuitId) {
404
- const response = await this.fetch(`/api/circuits/${encodeURIComponent(circuitId)}/activate`, {
402
+ return this.fetchJson(`/api/circuits/${encodeURIComponent(circuitId)}/activate`, {
405
403
  method: "POST"
406
404
  });
407
- return response.json();
408
405
  }
409
406
  // ==========================================================================
410
407
  // Shared Proof Methods
@@ -413,18 +410,19 @@ var BindClient = class {
413
410
  * Share a completed proof with a verifier organization
414
411
  * @param request - Share proof request with proveJobId and verifierOrgId
415
412
  * @returns The created shared proof
413
+ * @throws {ApiError} If the API request fails
416
414
  */
417
415
  async shareProof(request) {
418
- const response = await this.fetch("/api/shared-proofs", {
416
+ return this.fetchJson("/api/shared-proofs", {
419
417
  method: "POST",
420
418
  body: JSON.stringify(request)
421
419
  });
422
- return response.json();
423
420
  }
424
421
  /**
425
422
  * List shared proofs (outgoing or incoming)
426
423
  * @param options - Filter by direction, pagination, and inclusion options
427
424
  * @returns Paginated list of shared proofs
425
+ * @throws {ApiError} If the API request fails
428
426
  */
429
427
  async listSharedProofs(options = {}) {
430
428
  const params = new URLSearchParams();
@@ -435,28 +433,27 @@ var BindClient = class {
435
433
  if (options.includeRevoked) params.set("includeRevoked", "true");
436
434
  const queryString = params.toString();
437
435
  const path = queryString ? `/api/shared-proofs?${queryString}` : "/api/shared-proofs";
438
- const response = await this.fetch(path);
439
- return response.json();
436
+ return this.fetchJson(path);
440
437
  }
441
438
  /**
442
439
  * Get a specific shared proof by ID
443
440
  * @param sharedProofId - The shared proof ID
444
441
  * @returns The shared proof details
442
+ * @throws {ApiError} If the API request fails
445
443
  */
446
444
  async getSharedProof(sharedProofId) {
447
- const response = await this.fetch(`/api/shared-proofs/${encodeURIComponent(sharedProofId)}`);
448
- return response.json();
445
+ return this.fetchJson(`/api/shared-proofs/${encodeURIComponent(sharedProofId)}`);
449
446
  }
450
447
  /**
451
448
  * Revoke a shared proof. Only the sharing organization can revoke.
452
449
  * @param sharedProofId - The shared proof ID to revoke
453
450
  * @returns The revocation result
451
+ * @throws {ApiError} If the API request fails
454
452
  */
455
453
  async revokeSharedProof(sharedProofId) {
456
- const response = await this.fetch(`/api/shared-proofs/${encodeURIComponent(sharedProofId)}`, {
454
+ return this.fetchJson(`/api/shared-proofs/${encodeURIComponent(sharedProofId)}`, {
457
455
  method: "DELETE"
458
456
  });
459
- return response.json();
460
457
  }
461
458
  // ==========================================================================
462
459
  // Verification Methods
@@ -470,84 +467,70 @@ var BindClient = class {
470
467
  * @param sharedProofId - The shared proof ID to verify
471
468
  * @param options - Optional polling configuration
472
469
  * @returns The verification result
470
+ * @throws {ApiError} If the API request fails
471
+ * @throws {TimeoutError} If verification doesn't complete within the timeout
473
472
  */
474
473
  async verifySharedProof(sharedProofId, options) {
475
- const pollIntervalMs = options?.pollIntervalMs ?? 1e3;
476
- const maxWaitMs = options?.maxWaitMs ?? 12e4;
477
- const queueResponse = await this.fetch(`/api/verify/shared/${encodeURIComponent(sharedProofId)}`, {
474
+ const intervalMs = options?.intervalMs ?? 1e3;
475
+ const timeoutMs = options?.timeoutMs ?? 12e4;
476
+ const queueResult = await this.fetchJson(`/api/verify/shared/${encodeURIComponent(sharedProofId)}`, {
478
477
  method: "POST"
479
478
  });
480
- const queueResult = await queueResponse.json();
481
- if (!queueResult.success || !queueResult.data?.jobId) {
482
- return {
483
- success: false,
484
- error: queueResult.error ?? "Failed to queue verification job"
485
- };
486
- }
487
- const jobId = queueResult.data.jobId;
479
+ const jobId = queueResult.jobId;
488
480
  const startTime = Date.now();
489
- while (Date.now() - startTime < maxWaitMs) {
481
+ while (Date.now() - startTime < timeoutMs) {
490
482
  const statusResult = await this.getVerifyJobStatus(jobId);
491
- if (!statusResult.success) {
492
- return {
493
- success: false,
494
- error: statusResult.error ?? "Failed to get verification status"
495
- };
496
- }
497
- const status = statusResult.data?.status;
498
- if (status === "completed" || status === "failed") {
483
+ if (statusResult.status === "completed" || statusResult.status === "failed") {
499
484
  return {
500
- success: true,
501
- data: {
502
- isValid: statusResult.data?.isValid ?? false,
503
- error: statusResult.data?.error,
504
- verificationTimeMs: statusResult.data?.verificationTimeMs ?? 0,
505
- creditsCharged: statusResult.data?.creditsCharged ?? queueResult.data.creditsCharged,
506
- verificationResultId: statusResult.data?.verificationResultId ?? jobId,
507
- publicInputs: statusResult.data?.publicInputs
508
- }
485
+ isValid: statusResult.isValid ?? false,
486
+ error: statusResult.error,
487
+ verificationTimeMs: statusResult.verificationTimeMs ?? 0,
488
+ creditsCharged: statusResult.creditsCharged ?? queueResult.creditsCharged,
489
+ verificationResultId: statusResult.verificationResultId ?? jobId,
490
+ publicInputs: statusResult.publicInputs
509
491
  };
510
492
  }
511
- await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
493
+ await this.sleep(intervalMs);
512
494
  }
513
- return {
514
- success: false,
515
- error: `Verification timed out after ${maxWaitMs}ms. Job ID: ${jobId}`
516
- };
495
+ throw new TimeoutError(
496
+ `Verification timed out after ${timeoutMs}ms. Job ID: ${jobId}`,
497
+ timeoutMs
498
+ );
517
499
  }
518
500
  /**
519
501
  * Get the status of a verification job
520
502
  * @param jobId - The verification job ID
521
- * @returns The job status
503
+ * @returns The job status data
504
+ * @throws {ApiError} If the API request fails
522
505
  */
523
506
  async getVerifyJobStatus(jobId) {
524
- const response = await this.fetch(`/api/verify/jobs/${encodeURIComponent(jobId)}`);
525
- return response.json();
507
+ return this.fetchJson(`/api/verify/jobs/${encodeURIComponent(jobId)}`);
526
508
  }
527
509
  /**
528
510
  * Verify an uploaded proof
529
511
  * @param proofBuffer - The proof binary as ArrayBuffer, Uint8Array, or Buffer
530
512
  * @param vkBuffer - The verification key binary as ArrayBuffer, Uint8Array, or Buffer
531
513
  * @returns The verification result
514
+ * @throws {ApiError} If the API request fails
532
515
  */
533
516
  async verifyUploadedProof(proofBuffer, vkBuffer) {
534
517
  const proofBytes = proofBuffer instanceof Uint8Array ? proofBuffer : new Uint8Array(proofBuffer);
535
518
  const vkBytes = vkBuffer instanceof Uint8Array ? vkBuffer : new Uint8Array(vkBuffer);
536
519
  const proofBase64 = typeof Buffer !== "undefined" ? Buffer.from(proofBytes).toString("base64") : btoa(String.fromCharCode(...proofBytes));
537
520
  const vkBase64 = typeof Buffer !== "undefined" ? Buffer.from(vkBytes).toString("base64") : btoa(String.fromCharCode(...vkBytes));
538
- const response = await this.fetch("/api/verify/upload", {
521
+ return this.fetchJson("/api/verify/upload", {
539
522
  method: "POST",
540
523
  body: JSON.stringify({
541
524
  proof: proofBase64,
542
525
  vk: vkBase64
543
526
  })
544
527
  });
545
- return response.json();
546
528
  }
547
529
  /**
548
530
  * Get verification history for the authenticated organization
549
531
  * @param options - Pagination options
550
532
  * @returns Paginated list of verification results
533
+ * @throws {ApiError} If the API request fails
551
534
  */
552
535
  async getVerificationHistory(options = {}) {
553
536
  const params = new URLSearchParams();
@@ -555,8 +538,7 @@ var BindClient = class {
555
538
  if (options.offset !== void 0) params.set("offset", options.offset.toString());
556
539
  const queryString = params.toString();
557
540
  const path = queryString ? `/api/verify/history?${queryString}` : "/api/verify/history";
558
- const response = await this.fetch(path);
559
- return response.json();
541
+ return this.fetchJson(path);
560
542
  }
561
543
  // ==========================================================================
562
544
  // Private Helpers
@@ -572,8 +554,24 @@ var BindClient = class {
572
554
  if (response.status === 401) {
573
555
  throw new AuthenticationError();
574
556
  }
557
+ if (!response.ok) {
558
+ const body = await response.json().catch(() => ({}));
559
+ throw new ApiError(
560
+ body.error || `HTTP ${response.status}: ${response.statusText}`,
561
+ response.status,
562
+ body
563
+ );
564
+ }
575
565
  return response;
576
566
  }
567
+ async fetchJson(path, init) {
568
+ const response = await this.fetch(path, init);
569
+ const json = await response.json();
570
+ if (json.success === false) {
571
+ throw new ApiError(json.error || "Request failed", response.status, json);
572
+ }
573
+ return json.data ?? json;
574
+ }
577
575
  sleep(ms) {
578
576
  return new Promise((resolve) => setTimeout(resolve, ms));
579
577
  }
@@ -611,11 +609,7 @@ var ZkTlsAdapter = class {
611
609
  * Client should redirect user to this URL
612
610
  */
613
611
  async createSession(callbackUrl) {
614
- const result = await this.client.createZkTlsSession(this.extractorId, callbackUrl);
615
- if (!result.success || !result.data) {
616
- throw new Error(result.error || "Failed to create zkTLS session");
617
- }
618
- return result.data;
612
+ return this.client.createZkTlsSession(this.extractorId, callbackUrl);
619
613
  }
620
614
  /**
621
615
  * Wait for session completion and return attestation
@@ -626,7 +620,7 @@ var ZkTlsAdapter = class {
626
620
  throw new Error("Session completed but no attestation found");
627
621
  }
628
622
  const extractors = await this.client.listExtractors();
629
- const extractor = extractors.data?.find((e) => e.id === this.extractorId);
623
+ const extractor = extractors.find((e) => e.id === this.extractorId);
630
624
  if (!extractor) {
631
625
  throw new Error(`Extractor not found: ${this.extractorId}`);
632
626
  }
@@ -639,17 +633,14 @@ var ZkTlsAdapter = class {
639
633
  // Protected helpers
640
634
  // ===========================================================================
641
635
  async fetchExistingAttestation(attestationId) {
642
- const result = await this.client.getAttestation(attestationId);
643
- if (!result.success || !result.data) {
644
- throw new Error(result.error || "Attestation not found");
645
- }
636
+ const attestation = await this.client.getAttestation(attestationId);
646
637
  const extractors = await this.client.listExtractors();
647
- const extractor = extractors.data?.find((e) => e.id === result.data.extractor);
638
+ const extractor = extractors.find((e) => e.id === attestation.extractor);
648
639
  if (!extractor) {
649
- throw new Error(`Extractor not found: ${result.data.extractor}`);
640
+ throw new Error(`Extractor not found: ${attestation.extractor}`);
650
641
  }
651
642
  return {
652
- attestation: result.data,
643
+ attestation,
653
644
  extractor
654
645
  };
655
646
  }