@bind-protocol/sdk 0.9.0 → 0.11.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 (43) hide show
  1. package/dist/{adapter-qe9f1ll3.d.cts → adapter-BCmJtPVz.d.cts} +23 -9
  2. package/dist/{adapter-J6D9MZJV.d.ts → adapter-DEuMXI-G.d.ts} +23 -9
  3. package/dist/adapters/dimo/index.cjs +61 -10
  4. package/dist/adapters/dimo/index.cjs.map +1 -1
  5. package/dist/adapters/dimo/index.d.cts +32 -5
  6. package/dist/adapters/dimo/index.d.ts +32 -5
  7. package/dist/adapters/dimo/index.js +61 -11
  8. package/dist/adapters/dimo/index.js.map +1 -1
  9. package/dist/adapters/index.cjs +50 -12
  10. package/dist/adapters/index.cjs.map +1 -1
  11. package/dist/adapters/index.d.cts +5 -5
  12. package/dist/adapters/index.d.ts +5 -5
  13. package/dist/adapters/index.js +50 -12
  14. package/dist/adapters/index.js.map +1 -1
  15. package/dist/adapters/zktls/index.cjs +57 -2
  16. package/dist/adapters/zktls/index.cjs.map +1 -1
  17. package/dist/adapters/zktls/index.d.cts +18 -112
  18. package/dist/adapters/zktls/index.d.ts +18 -112
  19. package/dist/adapters/zktls/index.js +57 -3
  20. package/dist/adapters/zktls/index.js.map +1 -1
  21. package/dist/{client-CfYXpFLk.d.cts → client-D8RRkS5D.d.ts} +2 -2
  22. package/dist/{client-CpJ87Xe0.d.ts → client-Dwp_OgM8.d.cts} +2 -2
  23. package/dist/coinbase-D-ngYKTf.d.cts +116 -0
  24. package/dist/coinbase-tRHE5pGm.d.ts +116 -0
  25. package/dist/core/index.cjs +24 -2
  26. package/dist/core/index.cjs.map +1 -1
  27. package/dist/core/index.d.cts +2 -2
  28. package/dist/core/index.d.ts +2 -2
  29. package/dist/core/index.js +24 -2
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/index.cjs +411 -12
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +56 -6
  34. package/dist/index.d.ts +56 -6
  35. package/dist/index.js +406 -13
  36. package/dist/index.js.map +1 -1
  37. package/dist/types-BmMuzYu5.d.ts +64 -0
  38. package/dist/{types-D7Q7ymPa.d.ts → types-BmwJILOi.d.ts} +1 -1
  39. package/dist/types-CZN2fVZM.d.cts +64 -0
  40. package/dist/{types-ywkMNwun.d.cts → types-DLLfJJdQ.d.cts} +1 -1
  41. package/dist/{types-BcPssdQk.d.cts → types-YCc5fSja.d.cts} +1 -1
  42. package/dist/{types-BcPssdQk.d.ts → types-YCc5fSja.d.ts} +1 -1
  43. package/package.json +6 -1
package/dist/index.js CHANGED
@@ -430,18 +430,40 @@ var BindClient = class {
430
430
  * @returns The verification result
431
431
  * @throws {ApiError} If the API request fails
432
432
  */
433
- async verifyUploadedProof(proofBuffer, vkBuffer) {
433
+ async verifyUploadedProof(proofBuffer, vkBuffer, options) {
434
+ const intervalMs = options?.intervalMs ?? 1e3;
435
+ const timeoutMs = options?.timeoutMs ?? 12e4;
434
436
  const proofBytes = proofBuffer instanceof Uint8Array ? proofBuffer : new Uint8Array(proofBuffer);
435
437
  const vkBytes = vkBuffer instanceof Uint8Array ? vkBuffer : new Uint8Array(vkBuffer);
436
438
  const proofBase64 = typeof Buffer !== "undefined" ? Buffer.from(proofBytes).toString("base64") : btoa(String.fromCharCode(...proofBytes));
437
439
  const vkBase64 = typeof Buffer !== "undefined" ? Buffer.from(vkBytes).toString("base64") : btoa(String.fromCharCode(...vkBytes));
438
- return this.fetchJson("/api/verify/upload", {
440
+ const queueResult = await this.fetchJson("/api/verify/upload", {
439
441
  method: "POST",
440
442
  body: JSON.stringify({
441
443
  proof: proofBase64,
442
444
  vk: vkBase64
443
445
  })
444
446
  });
447
+ const jobId = queueResult.jobId;
448
+ const startTime = Date.now();
449
+ while (Date.now() - startTime < timeoutMs) {
450
+ const statusResult = await this.getVerifyJobStatus(jobId);
451
+ if (statusResult.status === "completed" || statusResult.status === "failed") {
452
+ return {
453
+ isValid: statusResult.isValid ?? false,
454
+ error: statusResult.error,
455
+ verificationTimeMs: statusResult.verificationTimeMs ?? 0,
456
+ creditsCharged: statusResult.creditsCharged ?? queueResult.creditsCharged,
457
+ verificationResultId: statusResult.verificationResultId ?? jobId,
458
+ publicInputs: statusResult.publicInputs
459
+ };
460
+ }
461
+ await this.sleep(intervalMs);
462
+ }
463
+ throw new TimeoutError(
464
+ `Verification timed out after ${timeoutMs}ms. Job ID: ${jobId}`,
465
+ timeoutMs
466
+ );
445
467
  }
446
468
  /**
447
469
  * Get verification history for the authenticated organization
@@ -503,12 +525,9 @@ function buildTelemetryQuery(vehicleTokenId, from, to) {
503
525
  from: ${from},
504
526
  to: ${to}
505
527
  ) {
506
- powertrainTransmissionTravelledDistance(agg: AVG)
507
- speed(agg: AVG)
508
- powertrainCombustionEngineSpeed(agg: AVG)
509
- obdEngineLoad(agg: AVG)
510
- obdDTCList(agg: UNIQUE)
511
- obdRunTime(agg: AVG)
528
+ powertrainTransmissionTravelledDistance(agg: SUM)
529
+ isIgnitionOn(agg: COUNT)
530
+ speed(agg: MAX)
512
531
  timestamp
513
532
  }
514
533
  }`;
@@ -535,7 +554,7 @@ ${signalLines}
535
554
 
536
555
  // src/adapters/dimo/adapter.ts
537
556
  var SUPPORTED_CIRCUITS = [
538
- "bind.mobility.riskband.v1"
557
+ "bind.dimo.riskband.v0_1_0"
539
558
  ];
540
559
  var DimoAdapter = class {
541
560
  id = "dimo";
@@ -568,7 +587,7 @@ var DimoAdapter = class {
568
587
  );
569
588
  }
570
589
  switch (circuitId) {
571
- case "bind.mobility.riskband.v1":
590
+ case "bind.dimo.riskband.v0_1_0":
572
591
  return this.toRiskBandInputs(data);
573
592
  default:
574
593
  throw new Error(`No input transformer for circuit: ${circuitId}`);
@@ -583,10 +602,29 @@ var DimoAdapter = class {
583
602
  // ===========================================================================
584
603
  // Private transformers
585
604
  // ===========================================================================
605
+ /**
606
+ * Aggregate hourly telemetry rows into the three circuit inputs
607
+ * required by bind.mobility.basicriskband:
608
+ *
609
+ * mileage_90d (u32) — SUM of powertrainTransmissionTravelledDistance
610
+ * data_points (u32) — COUNT of isIgnitionOn (sum of per-hour counts)
611
+ * speed_max (u16) — MAX of speed
612
+ */
586
613
  toRiskBandInputs(data) {
614
+ let mileageSum = 0;
615
+ let dataPointsSum = 0;
616
+ let speedMax = 0;
617
+ for (const row of data.signals) {
618
+ mileageSum += row.powertrainTransmissionTravelledDistance ?? 0;
619
+ dataPointsSum += row.isIgnitionOn ?? 0;
620
+ if ((row.speed ?? 0) > speedMax) {
621
+ speedMax = row.speed;
622
+ }
623
+ }
587
624
  return {
588
- signals: JSON.stringify(data.signals),
589
- timestamp: data.timestamp
625
+ mileage_90d: String(Math.round(mileageSum)),
626
+ data_points: String(Math.round(dataPointsSum)),
627
+ speed_max: String(Math.round(speedMax))
590
628
  };
591
629
  }
592
630
  };
@@ -594,6 +632,40 @@ function createDimoAdapter(config) {
594
632
  return new DimoAdapter(config);
595
633
  }
596
634
 
635
+ // src/adapters/dimo/fetcher.ts
636
+ var DimoSourceFetcher = class {
637
+ kind = "dimo";
638
+ adapter;
639
+ constructor(adapter) {
640
+ this.adapter = adapter;
641
+ }
642
+ async fetchSignals(_source, window, signals, context) {
643
+ const vehicleTokenId = context.subject["vehicleTokenId"];
644
+ if (!vehicleTokenId) {
645
+ throw new Error(
646
+ 'DimoSourceFetcher requires "vehicleTokenId" in context.subject'
647
+ );
648
+ }
649
+ const result = await this.adapter.fetchData({
650
+ vehicleTokenId,
651
+ from: window.from,
652
+ to: window.to
653
+ });
654
+ return result.signals.map((row) => {
655
+ const signal = {
656
+ timestamp: row.timestamp ?? result.timestamp
657
+ };
658
+ for (const key of signals) {
659
+ const value = row[key];
660
+ if (value !== void 0) {
661
+ signal[key] = value;
662
+ }
663
+ }
664
+ return signal;
665
+ });
666
+ }
667
+ };
668
+
597
669
  // src/adapters/zktls/adapter.ts
598
670
  var ZkTlsAdapter = class {
599
671
  client;
@@ -674,6 +746,38 @@ var ZkTlsAdapter = class {
674
746
  }
675
747
  };
676
748
 
749
+ // src/adapters/zktls/fetcher.ts
750
+ var ZkTlsSourceFetcher = class {
751
+ kind = "zktls";
752
+ adapter;
753
+ constructor(adapter) {
754
+ this.adapter = adapter;
755
+ }
756
+ async fetchSignals(_source, _window, signals, context) {
757
+ const attestationId = context.subject["attestationId"] ?? context.adapterContext?.["zktls"]?.["attestationId"];
758
+ const callbackUrl = context.adapterContext?.["zktls"]?.["callbackUrl"];
759
+ if (!attestationId && !callbackUrl) {
760
+ throw new Error(
761
+ 'ZkTlsSourceFetcher requires "attestationId" in context.subject or "attestationId"/"callbackUrl" in context.adapterContext.zktls'
762
+ );
763
+ }
764
+ const data = await this.adapter.fetchData({
765
+ attestationId,
766
+ callbackUrl
767
+ });
768
+ const claims = data.attestation.claims;
769
+ const timestamp = new Date(data.attestation.createdAt).toISOString();
770
+ const signal = { timestamp };
771
+ for (const key of signals) {
772
+ const value = claims[key];
773
+ if (value !== void 0) {
774
+ signal[key] = value;
775
+ }
776
+ }
777
+ return [signal];
778
+ }
779
+ };
780
+
677
781
  // src/adapters/zktls/coinbase.ts
678
782
  var SUPPORTED_CIRCUITS2 = [
679
783
  "bind.identity.kyc.v1",
@@ -737,6 +841,295 @@ function createCoinbaseAdapter(config) {
737
841
  return new CoinbaseAdapter(config);
738
842
  }
739
843
 
740
- export { ApiError, AuthenticationError, BindClient, BindError, CoinbaseAdapter, DimoAdapter, InsufficientCreditsError, TimeoutError, ZkTlsAdapter, ZkTlsExtractorError, ZkTlsSessionExpiredError, ZkTlsSessionFailedError, buildCustomTelemetryQuery, buildTelemetryQuery, createCoinbaseAdapter, createDimoAdapter, BindClient as default, deriveCircuitId };
844
+ // src/resolver/timeWindow.ts
845
+ var UNIT_MS = {
846
+ ms: 1,
847
+ s: 1e3,
848
+ m: 6e4,
849
+ h: 36e5,
850
+ d: 864e5,
851
+ w: 6048e5
852
+ };
853
+ function parseDuration(d) {
854
+ const match = /^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)$/.exec(d);
855
+ if (!match) {
856
+ throw new Error(`Invalid duration: "${d}". Expected format like "30d", "1h", "500ms".`);
857
+ }
858
+ const value = Number(match[1]);
859
+ const unit = match[2];
860
+ const multiplier = UNIT_MS[unit];
861
+ if (multiplier === void 0) {
862
+ throw new Error(`Unknown duration unit: "${unit}"`);
863
+ }
864
+ return value * multiplier;
865
+ }
866
+ function resolveTimeWindow(spec, now) {
867
+ switch (spec.mode) {
868
+ case "point":
869
+ return { from: spec.at, to: spec.at };
870
+ case "range":
871
+ return { from: spec.start, to: spec.end };
872
+ case "relative": {
873
+ const nowMs = (now ?? /* @__PURE__ */ new Date()).getTime();
874
+ const endOffsetMs = spec.endOffset ? parseDuration(spec.endOffset) : 0;
875
+ const toMs = nowMs - endOffsetMs;
876
+ const fromMs = toMs - parseDuration(spec.lookback);
877
+ return {
878
+ from: new Date(fromMs).toISOString(),
879
+ to: new Date(toMs).toISOString()
880
+ };
881
+ }
882
+ }
883
+ }
884
+
885
+ // src/resolver/aggregate.ts
886
+ function aggregate(signals, signalKey, spec) {
887
+ switch (spec.op) {
888
+ case "latest":
889
+ return aggregateLatest(signals, signalKey);
890
+ case "sum":
891
+ return aggregateSum(signals, signalKey);
892
+ case "avg":
893
+ return aggregateAvg(signals, signalKey);
894
+ case "min":
895
+ return aggregateMin(signals, signalKey);
896
+ case "max":
897
+ return aggregateMax(signals, signalKey);
898
+ case "count":
899
+ return aggregateCount(signals, signalKey);
900
+ case "distinctCount":
901
+ return aggregateDistinctCount(signals, signalKey);
902
+ case "p50":
903
+ case "p90":
904
+ case "p95":
905
+ case "p99":
906
+ return aggregatePercentile(signals, signalKey, spec.op);
907
+ case "windowedRate":
908
+ return aggregateWindowedRate(signals, signalKey, spec.per);
909
+ }
910
+ }
911
+ function extractNumericValues(signals, key) {
912
+ const values = [];
913
+ for (const s of signals) {
914
+ const v = s[key];
915
+ if (v != null && typeof v === "number") {
916
+ values.push(v);
917
+ } else if (v != null && typeof v === "string") {
918
+ const n = Number(v);
919
+ if (!Number.isNaN(n)) values.push(n);
920
+ }
921
+ }
922
+ return values;
923
+ }
924
+ function aggregateLatest(signals, key) {
925
+ const sorted = [...signals].sort(
926
+ (a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()
927
+ );
928
+ for (const s of sorted) {
929
+ const v = s[key];
930
+ if (v != null) return v;
931
+ }
932
+ throw new Error(`No non-null values found for signal "${key}" with op "latest"`);
933
+ }
934
+ function aggregateSum(signals, key) {
935
+ const values = extractNumericValues(signals, key);
936
+ let sum = 0;
937
+ for (const v of values) sum += v;
938
+ return sum;
939
+ }
940
+ function aggregateAvg(signals, key) {
941
+ const values = extractNumericValues(signals, key);
942
+ if (values.length === 0) return 0;
943
+ let sum = 0;
944
+ for (const v of values) sum += v;
945
+ return sum / values.length;
946
+ }
947
+ function aggregateMin(signals, key) {
948
+ const values = extractNumericValues(signals, key);
949
+ if (values.length === 0) return 0;
950
+ let min = values[0];
951
+ for (let i = 1; i < values.length; i++) {
952
+ if (values[i] < min) min = values[i];
953
+ }
954
+ return min;
955
+ }
956
+ function aggregateMax(signals, key) {
957
+ const values = extractNumericValues(signals, key);
958
+ if (values.length === 0) return 0;
959
+ let max = values[0];
960
+ for (let i = 1; i < values.length; i++) {
961
+ if (values[i] > max) max = values[i];
962
+ }
963
+ return max;
964
+ }
965
+ function aggregateCount(signals, key) {
966
+ let count = 0;
967
+ for (const s of signals) {
968
+ if (s[key] != null) count++;
969
+ }
970
+ return count;
971
+ }
972
+ function aggregateDistinctCount(signals, key) {
973
+ const unique = /* @__PURE__ */ new Set();
974
+ for (const s of signals) {
975
+ const v = s[key];
976
+ if (v != null && !Array.isArray(v)) unique.add(v);
977
+ }
978
+ return unique.size;
979
+ }
980
+ var PERCENTILE_MAP = {
981
+ p50: 0.5,
982
+ p90: 0.9,
983
+ p95: 0.95,
984
+ p99: 0.99
985
+ };
986
+ function aggregatePercentile(signals, key, op) {
987
+ const values = extractNumericValues(signals, key);
988
+ if (values.length === 0) return 0;
989
+ values.sort((a, b) => a - b);
990
+ const p = PERCENTILE_MAP[op];
991
+ const index = Math.ceil(p * values.length) - 1;
992
+ return values[Math.max(0, index)];
993
+ }
994
+ function aggregateWindowedRate(signals, key, per) {
995
+ if (signals.length === 0) return 0;
996
+ let count = 0;
997
+ for (const s of signals) {
998
+ if (s[key] != null) count++;
999
+ }
1000
+ const timestamps = signals.map((s) => new Date(s.timestamp).getTime()).filter((t) => !Number.isNaN(t));
1001
+ if (timestamps.length < 2) return count;
1002
+ const minTs = Math.min(...timestamps);
1003
+ const maxTs = Math.max(...timestamps);
1004
+ const spanMs = maxTs - minTs;
1005
+ if (spanMs === 0) return count;
1006
+ const perMs = parseDuration(per);
1007
+ return count / (spanMs / perMs);
1008
+ }
1009
+
1010
+ // src/resolver/InputResolver.ts
1011
+ function defaultStringify(value) {
1012
+ if (typeof value === "number") return String(Math.round(value));
1013
+ return String(value);
1014
+ }
1015
+ function buildGroupKey(spec, window) {
1016
+ return JSON.stringify({
1017
+ kind: spec.source.kind,
1018
+ ref: spec.source.ref ?? null,
1019
+ config: spec.source.config ?? null,
1020
+ from: window.from,
1021
+ to: window.to
1022
+ });
1023
+ }
1024
+ var InputResolver = class {
1025
+ fetchers;
1026
+ stringify;
1027
+ constructor(config) {
1028
+ this.fetchers = /* @__PURE__ */ new Map();
1029
+ for (const f of config.fetchers) {
1030
+ this.fetchers.set(f.kind, f);
1031
+ }
1032
+ this.stringify = config.stringify ?? ((v) => defaultStringify(v));
1033
+ }
1034
+ /**
1035
+ * Main entry point — resolves all inputs and returns Record<string, string>
1036
+ * ready for submitProveJob().
1037
+ */
1038
+ async resolveInputs(inputSpecs, context) {
1039
+ const resolved = await this.resolveAll(inputSpecs, context);
1040
+ const result = {};
1041
+ for (const r of resolved) {
1042
+ result[r.id] = r.rawValue;
1043
+ }
1044
+ return result;
1045
+ }
1046
+ /**
1047
+ * Detailed resolution — returns full ResolvedInput[] for debugging/inspection.
1048
+ */
1049
+ async resolveAll(inputSpecs, context) {
1050
+ const groups = this.groupInputs(inputSpecs, context);
1051
+ const signalsByGroup = await this.fetchAllGroups(groups, context);
1052
+ return this.aggregateAll(groups, signalsByGroup, inputSpecs);
1053
+ }
1054
+ /**
1055
+ * Group inputs by (source + time window) for batched fetching.
1056
+ */
1057
+ groupInputs(inputSpecs, context) {
1058
+ const groupMap = /* @__PURE__ */ new Map();
1059
+ for (const spec of inputSpecs) {
1060
+ const window = resolveTimeWindow(spec.time, context.now);
1061
+ const key = buildGroupKey(spec, window);
1062
+ let group = groupMap.get(key);
1063
+ if (!group) {
1064
+ group = {
1065
+ key,
1066
+ sourceKind: spec.source.kind,
1067
+ source: spec.source,
1068
+ window,
1069
+ inputs: [],
1070
+ signals: []
1071
+ };
1072
+ groupMap.set(key, group);
1073
+ }
1074
+ group.inputs.push(spec);
1075
+ if (!group.signals.includes(spec.signal)) {
1076
+ group.signals.push(spec.signal);
1077
+ }
1078
+ }
1079
+ return Array.from(groupMap.values());
1080
+ }
1081
+ /**
1082
+ * Fetch signals for all groups in parallel.
1083
+ */
1084
+ async fetchAllGroups(groups, context) {
1085
+ const results = /* @__PURE__ */ new Map();
1086
+ const fetches = groups.map(async (group) => {
1087
+ const fetcher = this.fetchers.get(group.sourceKind);
1088
+ if (!fetcher) {
1089
+ const registered = Array.from(this.fetchers.keys());
1090
+ throw new Error(
1091
+ `No SourceFetcher registered for kind "${group.sourceKind}". Registered kinds: [${registered.join(", ")}]`
1092
+ );
1093
+ }
1094
+ const signals = await fetcher.fetchSignals(
1095
+ group.source,
1096
+ group.window,
1097
+ group.signals,
1098
+ context
1099
+ );
1100
+ results.set(group.key, signals);
1101
+ });
1102
+ await Promise.all(fetches);
1103
+ return results;
1104
+ }
1105
+ /**
1106
+ * Apply aggregation to each input using the fetched signals.
1107
+ */
1108
+ aggregateAll(groups, signalsByGroup, inputSpecs) {
1109
+ const specMap = /* @__PURE__ */ new Map();
1110
+ for (const spec of inputSpecs) {
1111
+ specMap.set(spec.id, spec);
1112
+ }
1113
+ const resolved = [];
1114
+ for (const group of groups) {
1115
+ const signals = signalsByGroup.get(group.key) ?? [];
1116
+ for (const input of group.inputs) {
1117
+ const value = aggregate(signals, input.signal, input.aggregation);
1118
+ const spec = specMap.get(input.id);
1119
+ resolved.push({
1120
+ id: input.id,
1121
+ value,
1122
+ rawValue: this.stringify(value, spec),
1123
+ signal: input.signal,
1124
+ aggregationOp: input.aggregation.op,
1125
+ timeWindow: group.window
1126
+ });
1127
+ }
1128
+ }
1129
+ return resolved;
1130
+ }
1131
+ };
1132
+
1133
+ export { ApiError, AuthenticationError, BindClient, BindError, CoinbaseAdapter, DimoAdapter, DimoSourceFetcher, InputResolver, InsufficientCreditsError, TimeoutError, ZkTlsAdapter, ZkTlsExtractorError, ZkTlsSessionExpiredError, ZkTlsSessionFailedError, ZkTlsSourceFetcher, aggregate, buildCustomTelemetryQuery, buildTelemetryQuery, createCoinbaseAdapter, createDimoAdapter, BindClient as default, deriveCircuitId, parseDuration, resolveTimeWindow };
741
1134
  //# sourceMappingURL=index.js.map
742
1135
  //# sourceMappingURL=index.js.map