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