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