@tdxvolt/volt-client-grpc 0.17.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.cjs CHANGED
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var lodash = require('lodash');
6
6
  var ip = require('ip');
7
- var voltClientWeb = require('@tdxvolt/volt-client-web');
7
+ var js = require('@tdxvolt/volt-client-web/js');
8
8
  var debug = require('debug');
9
9
  var EventEmitter = require('events');
10
10
  var fs = require('fs');
@@ -17,27 +17,8 @@ var uuid = require('uuid');
17
17
 
18
18
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
19
19
 
20
- function _interopNamespace(e) {
21
- if (e && e.__esModule) return e;
22
- var n = Object.create(null);
23
- if (e) {
24
- Object.keys(e).forEach(function (k) {
25
- if (k !== 'default') {
26
- var d = Object.getOwnPropertyDescriptor(e, k);
27
- Object.defineProperty(n, k, d.get ? d : {
28
- enumerable: true,
29
- get: function () { return e[k]; }
30
- });
31
- }
32
- });
33
- }
34
- n["default"] = e;
35
- return Object.freeze(n);
36
- }
37
-
38
20
  var lodash__default = /*#__PURE__*/_interopDefaultLegacy(lodash);
39
21
  var ip__default = /*#__PURE__*/_interopDefaultLegacy(ip);
40
- var voltClientWeb__namespace = /*#__PURE__*/_interopNamespace(voltClientWeb);
41
22
  var debug__default = /*#__PURE__*/_interopDefaultLegacy(debug);
42
23
  var EventEmitter__default = /*#__PURE__*/_interopDefaultLegacy(EventEmitter);
43
24
  var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
@@ -46,60 +27,13 @@ var protoLoader__default = /*#__PURE__*/_interopDefaultLegacy(protoLoader);
46
27
  var bent__default = /*#__PURE__*/_interopDefaultLegacy(bent);
47
28
  var jwt__default = /*#__PURE__*/_interopDefaultLegacy(jwt);
48
29
 
49
- // eslint-disable-next-line import/prefer-default-export
50
30
  const constants = {
51
31
  authTokenName: "volt-token",
52
- collectionOperation: {
53
- add: "ADD",
54
- remove: "REMOVE",
55
- update: "UPDATE"
56
- },
57
- crypto: {
58
- subjectDefaults: [
59
- {
60
- name: "countryName",
61
- value: "GB"
62
- },
63
- {
64
- name: "localityName",
65
- value: "Southampton"
66
- },
67
- {
68
- name: "organizationName",
69
- value: "nquiringminds Ltd"
70
- }
71
- ],
72
- userIdOID: "0.9.2342.19200300.100.1.1"
73
- },
74
- defaultDIDHostName: "tdxvolt.com",
32
+ defaultDIDHostName: "coreid.com",
75
33
  didServiceType: {
76
34
  voltConfig: "volt-discovery"
77
35
  },
78
- identityType: {
79
- did: "did",
80
- volt: "volt"
81
- },
82
- onlineStatus: {
83
- offline: "offline",
84
- online: "online",
85
- unknown: "unknown"
86
- },
87
36
  privateEncryptedKeyPrefix: "-----BEGIN ENCRYPTED PRIVATE KEY-----",
88
- resource: {
89
- identity: "ident",
90
- identityView: "ident-view",
91
- proxy: "proxy",
92
- proxyView: "proxy-view",
93
- vc: "vc",
94
- vcView: "vc-view"
95
- },
96
- voltStatus: {
97
- pending: "",
98
- online: "online",
99
- offline: "offline",
100
- deleted: "deleted",
101
- revoked: "revoked"
102
- },
103
37
  /**
104
38
  * These top-level service types should map to a protobuf definition
105
39
  * in @tdxvolt/volt-proto.
@@ -112,12 +46,7 @@ const constants = {
112
46
  relayAPI: "tdx.volt_api.relay.v1.RelayAPI",
113
47
  voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
114
48
  wireAPI: "tdx.volt_api.volt.v1.WireAPI"
115
- },
116
- tunnelInvokeMethod: "/tdx.volt_api.volt.v1.VoltAPI/Invoke",
117
- tunnelPingInterval: 10000,
118
- tunnelPingTimeout: 2500,
119
- tunnelReconnectAfter: 30000,
120
- tunnelTimeoutInterval: 10000 * 2 // This must always be greater than `tunnelPingInterval`.
49
+ }
121
50
  };
122
51
 
123
52
  const createSecureContextOptions = (cryptoOptions) => {
@@ -172,7 +101,7 @@ var utils = /*#__PURE__*/Object.freeze({
172
101
  createSecureContextOptions: createSecureContextOptions,
173
102
  getServiceAddress: getServiceAddress,
174
103
  getDIDResolutionURL: getDIDResolutionURL,
175
- crypto: voltClientWeb__namespace
104
+ crypto: js.voltUtils
176
105
  });
177
106
 
178
107
  /* eslint-disable no-underscore-dangle */
@@ -194,7 +123,7 @@ function createClient(
194
123
  ) {
195
124
  let grpcCredentials;
196
125
  if (credentials) {
197
- const relaying = !!credentials.config?.volt?.relay;
126
+ const relaying = !!credentials.config?.volt?.relay && !Array.isArray(credentials.config?.volt?.relay);
198
127
  const ca = relaying
199
128
  ? credentials.config?.volt?.relay?.ca_pem
200
129
  : credentials.cache.ca;
@@ -202,8 +131,8 @@ function createClient(
202
131
  const { key } = credentials.cache;
203
132
 
204
133
  if (key && cert) {
205
- const cryyptoOptions = { ca, cert, key };
206
- const tlsOptions = createSecureContextOptions(cryyptoOptions);
134
+ const cryptoOptions = { ca, cert, key };
135
+ const tlsOptions = createSecureContextOptions(cryptoOptions);
207
136
  grpcCredentials = grpc.credentials.createSsl(
208
137
  tlsOptions.ca,
209
138
  tlsOptions.key,
@@ -418,6 +347,15 @@ var grpcUtils = /*#__PURE__*/Object.freeze({
418
347
 
419
348
  /* eslint-disable no-underscore-dangle */
420
349
 
350
+ const {
351
+ createSigningKey,
352
+ fingerprintFromPem,
353
+ getIdentityToken,
354
+ keyFromPem: keyFromPem$2,
355
+ privateKeyToPem,
356
+ publicKeyToPem: publicKeyToPem$2
357
+ } = js.voltUtils;
358
+
421
359
  const log$5 = debug__default["default"]("volt-client-grpc:volt-credential");
422
360
 
423
361
  class VoltCredential {
@@ -442,13 +380,13 @@ class VoltCredential {
442
380
  }
443
381
 
444
382
  // Need to unencrypt the private key.
445
- const decrypted = voltClientWeb.keyFromPem(this._cryptoCache.key, config.p);
383
+ const decrypted = keyFromPem$2(this._cryptoCache.key, config.p);
446
384
 
447
385
  if (!decrypted) {
448
386
  throw new Error("failed to decrypt key - check passphrase");
449
387
  }
450
388
 
451
- this._cryptoCache.key = voltClientWeb.privateKeyToPem(decrypted.privateKey);
389
+ this._cryptoCache.key = privateKeyToPem(decrypted.privateKey);
452
390
  }
453
391
 
454
392
  if (this._voltConfig.ca_pem) {
@@ -457,11 +395,11 @@ class VoltCredential {
457
395
  this._cryptoCache.ca = this._voltConfig.ca_pem;
458
396
  }
459
397
 
460
- // Extract Volt public key (used for encrypting Relay payloads).
398
+ // Extract Volt public key.
461
399
  this._voltPublicKey = this._voltConfig.public_key;
462
400
 
463
- const voltKey = voltClientWeb.keyFromPem(this._voltPublicKey).publicKey;
464
- this._voltFingerprint = voltClientWeb.fingerprintFromPublicKey(voltKey);
401
+ const voltKey = keyFromPem$2(this._voltPublicKey).publicKey;
402
+ this._voltFingerprint = fingerprintFromPem(voltKey);
465
403
  }
466
404
  }
467
405
 
@@ -490,15 +428,19 @@ class VoltCredential {
490
428
  }
491
429
 
492
430
  get publicKey() {
493
- return voltClientWeb.publicKeyToPem(this.getKey().publicKey);
431
+ return publicKeyToPem$2(this.getKey().publicKey);
494
432
  }
495
433
 
496
434
  get voltFingerprint() {
497
435
  return this._voltFingerprint;
498
436
  }
499
437
 
438
+ get key() {
439
+ return this.getKey();
440
+ }
441
+
500
442
  getKey() {
501
- const key = voltClientWeb.keyFromPem(this._cryptoCache.key);
443
+ const key = keyFromPem$2(this._cryptoCache.key);
502
444
  return key;
503
445
  }
504
446
 
@@ -512,8 +454,8 @@ class VoltCredential {
512
454
  return Promise.resolve(this.getKey());
513
455
  } else {
514
456
  log$5("creating key");
515
- this._cryptoCache.key = voltClientWeb.createKey();
516
- const key = voltClientWeb.keyFromPem(this._cryptoCache.key);
457
+ this._cryptoCache.key = JSON.parse(createSigningKey()).private_pem;
458
+ const key = keyFromPem$2(this._cryptoCache.key);
517
459
  log$5("successfully created key");
518
460
  return Promise.resolve(key);
519
461
  }
@@ -550,9 +492,9 @@ class VoltCredential {
550
492
  * @returns
551
493
  */
552
494
  getIdentityMetadata(grpc, audience, publicKey, tunnelling = false, ttl = 60) {
553
- const key = voltClientWeb.keyFromPem(this._cryptoCache.key);
495
+ const key = keyFromPem$2(this._cryptoCache.key);
554
496
 
555
- const identityToken = voltClientWeb.getIdentityToken(
497
+ const identityToken = getIdentityToken(
556
498
  this.sessionId,
557
499
  key,
558
500
  audience || this._voltConfig.id,
@@ -568,8 +510,8 @@ class VoltCredential {
568
510
  const clone = { ...this._config, credential: { ...this._cryptoCache } };
569
511
  if (this._config.p) {
570
512
  // A passphrase option exists => encrypt the key before writing the cache file.
571
- const key = voltClientWeb.keyFromPem(this._cryptoCache.key);
572
- clone.credential.key = voltClientWeb.privateKeyToPem(key.privateKey, this._config.p);
513
+ const key = keyFromPem$2(this._cryptoCache.key);
514
+ clone.credential.key = privateKeyToPem(key.privateKey, this._config.p);
573
515
  }
574
516
 
575
517
  if (this._persistCache) {
@@ -708,6 +650,20 @@ var protoUtils = /*#__PURE__*/Object.freeze({
708
650
 
709
651
  /* eslint-disable no-underscore-dangle */
710
652
 
653
+ const {
654
+ aesCreateKey,
655
+ aesEncrypt: aesEncrypt$1,
656
+ aesDecrypt: aesDecrypt$1,
657
+ toBase64,
658
+ formatPEM: formatPEM$1,
659
+ keyFromPem: keyFromPem$1,
660
+ verify,
661
+ deriveSharedKey: deriveSharedKey$1,
662
+ x25519: x25519$1
663
+ } = js.voltUtils;
664
+
665
+ const invokeMethod = "Invoke";
666
+
711
667
  const log$4 = debug__default["default"]("volt-client-grpc:grpc-call");
712
668
 
713
669
  function _prepareInvokeRequest(
@@ -719,10 +675,10 @@ function _prepareInvokeRequest(
719
675
  this._service?.service_description.host_type ===
720
676
  "SERVICE_HOST_TYPE_RELAYED";
721
677
 
722
- const relaying = this._voltClient.isVoltRelay || isServiceRelayed;
678
+ const relaying = this._voltClient.isRelayed || isServiceRelayed;
723
679
 
724
680
  let targetDID = [];
725
- if (this._voltClient.isVoltRelay) {
681
+ if (this._voltClient.isRelayed) {
726
682
  targetDID.push(this._voltClient.voltConfig.id);
727
683
  }
728
684
 
@@ -747,20 +703,23 @@ function _prepareInvokeRequest(
747
703
  let invokeRequest;
748
704
  let callMethod = method;
749
705
 
706
+ const voltGrpcClient = this._voltClient.getVoltAPIClient();
707
+
750
708
  if (relaying) {
751
709
  //
752
710
  // If the volt connection is via a relay (or the target service is relayed),
753
711
  // we wrap the rpc in a RemoteRequest message and send it via a call to Invoke().
754
712
  //
713
+
755
714
  // Replace the target method with a call to Invoke on the relay Volt.
756
- //
757
- callMethod = "Invoke";
715
+ callMethod = invokeMethod;
758
716
 
759
717
  // But first we need to perform a key exchange with the target service.
760
- //
761
718
  if (!this._encryptionKey) {
762
719
  // We haven't exchanged keys yet, so queue the payload.
763
- this._pendingRequests.push(request);
720
+ if (request) {
721
+ this._pendingRequests.push(request);
722
+ }
764
723
 
765
724
  if (this._keyExchangePending) {
766
725
  // We've already sent the key exchange request, so do nothing.
@@ -779,6 +738,13 @@ function _prepareInvokeRequest(
779
738
  : undefined
780
739
  };
781
740
 
741
+ if (this._voltClient.isRelayed) {
742
+ // When tunnelling, we serialise the request using the original serialisation
743
+ // method for Invoke.
744
+ invokeRequest =
745
+ voltGrpcClient.Invoke.requestSerializeOriginal(invokeRequest);
746
+ }
747
+
782
748
  return {
783
749
  request: invokeRequest,
784
750
  method: callMethod,
@@ -789,41 +755,45 @@ function _prepareInvokeRequest(
789
755
 
790
756
  let requestPayload;
791
757
 
792
- // Serialise the rpc request.
758
+ // Serialise the rpc request using the original serialisation method.
793
759
  if (request) {
794
- requestPayload = this._grpcClient[method].requestSerialize(request);
760
+ if (this._voltClient.isRelayed) {
761
+ requestPayload =
762
+ this._grpcClient[method].requestSerializeOriginal(request);
763
+ } else {
764
+ requestPayload = this._grpcClient[method].requestSerialize(request);
765
+ }
795
766
  } else if (request !== null) {
796
767
  log$4("****************LOOKOUT****************** - empty request");
797
768
  } else {
798
769
  log$4("explicit empty request payload");
799
770
  }
800
771
 
801
- // Use this placeholder to serialise the relay request wrapper.
802
- const voltGrpcClient = this._voltClient.getVoltAPIClient();
803
- const tunnelMethod = voltGrpcClient.Tunnel;
804
-
805
- const tunnelResp = {
772
+ // Create a tunnel message containing the method call metadata and request payload.
773
+ const tunnelResp = voltGrpcClient.Tunnel.responseSerialize({
806
774
  method_invoke: {
807
775
  method_name: this._grpcClient[method].path,
808
776
  method_type: methodType,
809
777
  request: requestPayload
810
778
  }
811
- };
812
-
813
- let invokePayload;
814
- const iv = voltClientWeb.aesCreateKey().iv;
779
+ });
815
780
 
816
781
  // When sending via a relay we need to encrypt the payload.
817
- invokePayload = voltClientWeb.aesEncrypt(
818
- this._encryptionKey,
819
- iv,
820
- tunnelMethod.responseSerialize(tunnelResp)
821
- );
782
+ const iv = aesCreateKey().iv;
783
+ const invokePayload = aesEncrypt$1(this._encryptionKey, iv, tunnelResp);
822
784
 
785
+ // Construct the Invoke request.
823
786
  invokeRequest = {
824
787
  iv,
825
788
  payload: invokePayload
826
789
  };
790
+
791
+ if (this._voltClient.isRelayed) {
792
+ // When tunnelling, we serialise the request using the original serialisation
793
+ // method for Invoke.
794
+ invokeRequest =
795
+ voltGrpcClient.Invoke.requestSerializeOriginal(invokeRequest);
796
+ }
827
797
  } else {
828
798
  invokeRequest = request;
829
799
  }
@@ -843,32 +813,45 @@ function _preparePayloadRequest(request, invokeInfo) {
843
813
  this._service?.service_description.host_type ===
844
814
  "SERVICE_HOST_TYPE_RELAYED";
845
815
 
846
- let iv;
847
- if (this._voltClient.isVoltRelay || isServiceRelayed) {
848
- iv = voltClientWeb.aesCreateKey().iv;
849
-
850
- const requestPayload =
851
- this._grpcClient[invokeInfo.methodName].requestSerialize(request);
816
+ if (this._voltClient.isRelayed || isServiceRelayed) {
817
+ let requestPayload;
818
+ if (this._voltClient.isRelayed) {
819
+ // Serialise the rpc request using the original serialisation method.
820
+ requestPayload =
821
+ this._grpcClient[invokeInfo.methodName].requestSerializeOriginal(
822
+ request
823
+ );
824
+ } else {
825
+ requestPayload =
826
+ this._grpcClient[invokeInfo.methodName].requestSerialize(request);
827
+ }
852
828
 
829
+ // Use the Tunnel method to serialise the relay request wrapper, this
853
830
  const voltGrpcClient = this._voltClient.getVoltAPIClient();
854
- const tunnelMethod = voltGrpcClient.Tunnel;
855
831
 
856
- const tunnelResp = {
832
+ // Create a tunnel message containing the method call metadata and request payload.
833
+ const tunnelResp = voltGrpcClient.Tunnel.responseSerialize({
857
834
  method_payload: {
858
835
  payload: requestPayload
859
836
  }
860
- };
837
+ });
861
838
 
862
- const invokePayload = voltClientWeb.aesEncrypt(
863
- this._encryptionKey,
864
- iv,
865
- tunnelMethod.responseSerialize(tunnelResp)
866
- );
839
+ // Encrypt the payload using the shared key.
840
+ const iv = aesCreateKey().iv;
841
+ const invokePayload = aesEncrypt$1(this._encryptionKey, iv, tunnelResp);
867
842
 
843
+ // We then serialise the entire request using the original serialisation method for Invoke.
868
844
  payloadRequest = {
869
845
  iv,
870
846
  payload: invokePayload
871
847
  };
848
+
849
+ if (this._voltClient.isRelayed) {
850
+ // When tunnelling, we serialise the request using the original serialisation
851
+ // method for Invoke.
852
+ payloadRequest =
853
+ voltGrpcClient.Invoke.requestSerializeOriginal(payloadRequest);
854
+ }
872
855
  } else {
873
856
  payloadRequest = request;
874
857
  }
@@ -884,7 +867,14 @@ function _parseResponse(method, meta, response) {
884
867
  this._service?.service_description.host_type ===
885
868
  "SERVICE_HOST_TYPE_RELAYED";
886
869
 
887
- if (this._voltClient.isVoltRelay || isServiceRelayed) {
870
+ const voltGrpcClient = this._voltClient.getVoltAPIClient();
871
+
872
+ if (this._voltClient.isRelayed || isServiceRelayed) {
873
+ if (this._voltClient.isRelayed) {
874
+ // Deserialise the incoming response using the original deserialisation method for Invoke.
875
+ response = voltGrpcClient.Invoke.responseDeserializeOriginal(response);
876
+ }
877
+
888
878
  if (response.key_exchange) {
889
879
  const encryptionKey = response.key_exchange.encryption_key;
890
880
  const nonce = response.key_exchange.nonce;
@@ -896,24 +886,24 @@ function _parseResponse(method, meta, response) {
896
886
  message.set(nonce, encryptionKey.length);
897
887
 
898
888
  // Check the signature using the target service public key.
899
- const targetKey = voltClientWeb.keyFromPem(
889
+ const targetKey = keyFromPem$1(
900
890
  this._service?.service_description?.host_public_key ||
901
891
  this._voltClient.credential.voltPublicKey
902
892
  ).publicKey;
903
893
 
904
- if (!voltClientWeb.verify(targetKey, message, signature)) {
894
+ if (!verify(targetKey, message, signature)) {
905
895
  throw new Error("signature verification failed");
906
896
  }
907
897
 
908
898
  invokeResponse = {
909
899
  key_exchange: {
910
- encryption_key: voltClientWeb.formatPEM(voltClientWeb.toBase64(encryptionKey), "PUBLIC KEY")
900
+ encryption_key: formatPEM$1(toBase64(encryptionKey), "PUBLIC KEY")
911
901
  }
912
902
  };
913
903
  } else if (response.payload) {
914
904
  let decryptedPayload;
915
905
  if (this._encryptionKey) {
916
- decryptedPayload = voltClientWeb.aesDecrypt(
906
+ decryptedPayload = aesDecrypt$1(
917
907
  this._encryptionKey,
918
908
  response.iv,
919
909
  response.payload
@@ -922,13 +912,24 @@ function _parseResponse(method, meta, response) {
922
912
  decryptedPayload = response.payload;
923
913
  }
924
914
 
925
- const tunnelMethod = this._voltClient.getVoltAPIClient().Tunnel;
926
- const responsePayload = tunnelMethod.requestDeserialize(decryptedPayload);
915
+ // Deserialise the decrypted payload using the Tunnel deserialisation method.
916
+ const responsePayload =
917
+ voltGrpcClient.Tunnel.requestDeserialize(decryptedPayload);
927
918
  if (responsePayload.payload === "method_payload") {
928
919
  try {
929
- invokeResponse.payload = this._grpcClient[method].responseDeserialize(
930
- responsePayload.method_payload.payload
931
- );
920
+ // Deserialise the method payload.
921
+ if (this._voltClient.isRelayed) {
922
+ // Use the original deserialisation method for the target method.
923
+ invokeResponse.payload = this._grpcClient[
924
+ method
925
+ ].responseDeserializeOriginal(
926
+ responsePayload.method_payload.payload
927
+ );
928
+ } else {
929
+ invokeResponse.payload = this._grpcClient[
930
+ method
931
+ ].responseDeserialize(responsePayload.method_payload.payload);
932
+ }
932
933
  } catch (err) {
933
934
  log$4("failure deserialising payload for %s", this._methodName);
934
935
  throw new Error(
@@ -956,16 +957,6 @@ function _parseResponse(method, meta, response) {
956
957
  invokeResponse.methodId = response.invoke_id;
957
958
  log$4("started method %d for %s", invokeResponse.methodId, method);
958
959
  }
959
- } else if (this._voltClient.isRemote && this._encryptionKey) {
960
- const decryptedPayload = voltClientWeb.aesDecrypt(
961
- this._encryptionKey,
962
- meta.sharedKey.iv,
963
- response
964
- );
965
- invokeResponse = {
966
- payload:
967
- this._grpcClient[method].responseDeserializeOriginal(decryptedPayload)
968
- };
969
960
  } else {
970
961
  invokeResponse = { payload: response };
971
962
  }
@@ -1005,7 +996,7 @@ class GRPCCall extends EventEmitter__default["default"] {
1005
996
  "SERVICE_HOST_TYPE_RELAYED";
1006
997
 
1007
998
  let callClient;
1008
- if (this._voltClient.isVoltRelay || isServiceRelayed) {
999
+ if (this._voltClient.isRelayed || isServiceRelayed) {
1009
1000
  callClient = this._voltClient.getVoltAPIClient();
1010
1001
  } else {
1011
1002
  callClient = this._grpcClient;
@@ -1024,14 +1015,14 @@ class GRPCCall extends EventEmitter__default["default"] {
1024
1015
  streamResponse
1025
1016
  );
1026
1017
  if (parsedResponse.key_exchange) {
1027
- const peerKey = voltClientWeb.keyFromPem(
1018
+ const peerKey = keyFromPem$1(
1028
1019
  parsedResponse.key_exchange.encryption_key
1029
1020
  ).publicKey;
1030
1021
 
1031
- this._encryptionKey = voltClientWeb.deriveSharedKey(
1022
+ this._encryptionKey = deriveSharedKey$1(
1032
1023
  this._initialRequest.meta.sharedKey.key,
1033
1024
  peerKey,
1034
- voltClientWeb.x25519
1025
+ x25519$1
1035
1026
  );
1036
1027
 
1037
1028
  // We've exchanged keys, so send any queued payloads on the next tick.
@@ -1072,7 +1063,11 @@ class GRPCCall extends EventEmitter__default["default"] {
1072
1063
  });
1073
1064
 
1074
1065
  this._call.on("error", (err) => {
1075
- log$4("ERROR - intercepted stream error %s", err.message);
1066
+ log$4(
1067
+ "ERROR - intercepted stream error on %s: %s",
1068
+ this._methodName,
1069
+ err.message
1070
+ );
1076
1071
  this.emit("error", err);
1077
1072
  });
1078
1073
 
@@ -1108,6 +1103,16 @@ class GRPCCall extends EventEmitter__default["default"] {
1108
1103
  }
1109
1104
  }
1110
1105
 
1106
+ pause() {
1107
+ log$4("pausing call %s", this._methodName);
1108
+ return this._call?.pause();
1109
+ }
1110
+
1111
+ resume() {
1112
+ log$4("resuming call %s", this._methodName);
1113
+ return this._call?.resume();
1114
+ }
1115
+
1111
1116
  get writable() {
1112
1117
  return this._call?.writable;
1113
1118
  }
@@ -1232,8 +1237,18 @@ function _doConnect(connectHello) {
1232
1237
  break;
1233
1238
  }
1234
1239
  case "invoke_request": {
1235
- log$3("received invoke request");
1236
- this.emit("invoke_request", response.invoke_request);
1240
+ log$3("received invoke request %s", response.invoke_request.invoke_id);
1241
+ // Pause the call while we process the invoke request to avoid getting
1242
+ // CANCELLED errors from grpc - we should perhaps leave this to the
1243
+ // client to manage as it may be overkill in some cases.
1244
+ this.call.pause();
1245
+ try {
1246
+ this.emit("invoke_request", response.invoke_request);
1247
+ } catch (err) {
1248
+ log$3("error processing invoke request [%s]", err.message);
1249
+ } finally {
1250
+ this.call.resume();
1251
+ }
1237
1252
  break;
1238
1253
  }
1239
1254
  case "evt": {
@@ -1305,6 +1320,10 @@ class VoltConnection extends EventEmitter__default["default"] {
1305
1320
  this._helloPayload = undefined;
1306
1321
  }
1307
1322
 
1323
+ get connectionId() {
1324
+ return this._connectionId;
1325
+ }
1326
+
1308
1327
  connect(helloPayload, throwOnFail) {
1309
1328
  this._helloPayload = helloPayload;
1310
1329
  if (throwOnFail) {
@@ -1324,19 +1343,38 @@ class VoltConnection extends EventEmitter__default["default"] {
1324
1343
  }
1325
1344
  }
1326
1345
 
1327
- const log$2 = debug__default["default"]("rpc-invocation");
1346
+ const {
1347
+ aesDecrypt,
1348
+ aesEncrypt,
1349
+ createEncryptionKey,
1350
+ deriveSharedKey,
1351
+ formatPEM,
1352
+ fromBase64,
1353
+ fromBase64Url,
1354
+ keyFromPem,
1355
+ publicKeyToPem: publicKeyToPem$1,
1356
+ randomBytes,
1357
+ signBase64: signBase64$1,
1358
+ stripPemHeaders,
1359
+ x25519
1360
+ } = js.voltUtils;
1361
+
1362
+ const log$2 = debug__default["default"]("volt-client-grpc:rpc-invocation");
1328
1363
 
1329
1364
  class RpcInvocation extends EventEmitter__default["default"] {
1330
1365
  #voltClient = null;
1331
1366
  #voltConnection = null;
1332
1367
  #token = null;
1368
+ #callerPublicKeyPem = null;
1333
1369
  #invokeId = null;
1370
+ #serviceId = null;
1334
1371
  #payload = null;
1335
1372
  #isJSON = false;
1336
1373
  #methodDescriptor = null;
1337
1374
  #methodName = null;
1338
1375
  #derivedKey = null;
1339
1376
  #started = false;
1377
+ #endEmitted = false;
1340
1378
 
1341
1379
  constructor(voltClient, voltConnection) {
1342
1380
  super();
@@ -1348,6 +1386,18 @@ class RpcInvocation extends EventEmitter__default["default"] {
1348
1386
  return this.#invokeId;
1349
1387
  }
1350
1388
 
1389
+ get serviceId() {
1390
+ return this.#serviceId;
1391
+ }
1392
+
1393
+ get token() {
1394
+ return this.#token;
1395
+ }
1396
+
1397
+ get callerPublicKeyPem() {
1398
+ return this.#callerPublicKeyPem;
1399
+ }
1400
+
1351
1401
  get payload() {
1352
1402
  if (!this.#payload) {
1353
1403
  return null;
@@ -1389,31 +1439,40 @@ class RpcInvocation extends EventEmitter__default["default"] {
1389
1439
  // The rpc implementation should do the verification using the Volt API (e.g. CanAccessResource).
1390
1440
  this.#token = jwt__default["default"].decode(token);
1391
1441
 
1392
- // Store the JWT key id (kid) for use in the response.
1393
- const callerPublicKeyPem = voltClientWeb.formatPEM(this.#token.k, "PUBLIC KEY");
1394
- const callerKey = voltClientWeb.keyFromPem(callerPublicKeyPem, "", voltClientWeb.x25519).publicKey;
1442
+ if (!this.#token) {
1443
+ log$2("failed to decode token %s", token || "null");
1444
+ return Promise.reject(new Error("failed to decode token"));
1445
+ }
1395
1446
 
1396
- const ephemeralKeyPem = voltClientWeb.createEncryptionKey();
1397
- const ephemeralKey = voltClientWeb.keyFromPem(ephemeralKeyPem, "", voltClientWeb.x25519);
1398
- const ephemeralPublicKey = voltClientWeb.fromBase64(
1399
- voltClientWeb.stripPEMHeaders(voltClientWeb.publicKeyToPem(ephemeralKey.publicKey, voltClientWeb.x25519))
1447
+ // Store the JWT key id (kid) for use in the response.
1448
+ this.#callerPublicKeyPem = formatPEM(this.#token.k, "PUBLIC KEY");
1449
+ const callerKey = keyFromPem(
1450
+ this.#callerPublicKeyPem,
1451
+ "",
1452
+ x25519
1453
+ ).publicKey;
1454
+
1455
+ const ephemeralKeyPem = createEncryptionKey();
1456
+ const ephemeralKey = keyFromPem(ephemeralKeyPem, "", x25519);
1457
+ const ephemeralPublicKey = fromBase64(
1458
+ stripPemHeaders(publicKeyToPem$1(ephemeralKey.publicKey, x25519))
1400
1459
  );
1401
1460
 
1402
- this.#derivedKey = voltClientWeb.deriveSharedKey(
1461
+ this.#derivedKey = deriveSharedKey(
1403
1462
  ephemeralKey.privateKey,
1404
1463
  callerKey,
1405
- voltClientWeb.x25519
1464
+ x25519
1406
1465
  );
1407
1466
 
1408
- const nonce = voltClientWeb.randomBytes(16);
1467
+ const nonce = randomBytes(16);
1409
1468
 
1410
1469
  // The signed message is the encryption key and the nonce.
1411
1470
  const message = new Uint8Array(ephemeralPublicKey.length + nonce.length);
1412
1471
  message.set(ephemeralPublicKey);
1413
1472
  message.set(nonce, ephemeralPublicKey.length);
1414
1473
 
1415
- const signature = voltClientWeb.signBase64(
1416
- this.#voltClient.credential.getKey().privateKey,
1474
+ const signature = signBase64$1(
1475
+ this.#voltClient.credential.cache.key,
1417
1476
  message
1418
1477
  );
1419
1478
 
@@ -1422,7 +1481,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
1422
1481
  key_exchange: {
1423
1482
  nonce,
1424
1483
  encryption_key: ephemeralPublicKey,
1425
- signature: voltClientWeb.fromBase64Url(signature)
1484
+ signature: fromBase64Url(signature)
1426
1485
  }
1427
1486
  };
1428
1487
 
@@ -1434,7 +1493,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
1434
1493
  }
1435
1494
 
1436
1495
  initialise(invoke_request) {
1437
- this.#invokeId = invoke_request.invoke_id;
1496
+ if (!this.#invokeId) {
1497
+ this.#invokeId = invoke_request.invoke_id;
1498
+ this.#serviceId = invoke_request.target_service_id;
1499
+ }
1438
1500
 
1439
1501
  if (!this.#derivedKey) {
1440
1502
  // We don't have the derived key yet, so we need to perform the key exchange.
@@ -1456,10 +1518,9 @@ class RpcInvocation extends EventEmitter__default["default"] {
1456
1518
 
1457
1519
  if (invoke_request.payload) {
1458
1520
  let decryptedPayload;
1459
-
1460
- if (encryptIV) {
1521
+ if (encryptIV?.length) {
1461
1522
  // Decrypt the actual payload using the shared key and iv.
1462
- decryptedPayload = voltClientWeb.aesDecrypt(
1523
+ decryptedPayload = aesDecrypt(
1463
1524
  this.#derivedKey,
1464
1525
  encryptIV,
1465
1526
  invoke_request.payload
@@ -1500,7 +1561,7 @@ class RpcInvocation extends EventEmitter__default["default"] {
1500
1561
 
1501
1562
  if (this.#derivedKey) {
1502
1563
  // Decrypt the actual payload using the shared key and iv.
1503
- decryptedPayload = voltClientWeb.aesDecrypt(
1564
+ decryptedPayload = aesDecrypt(
1504
1565
  this.#derivedKey,
1505
1566
  invoke_request.iv,
1506
1567
  Buffer.from(invoke_request.json_payload, "base64")
@@ -1525,8 +1586,13 @@ class RpcInvocation extends EventEmitter__default["default"] {
1525
1586
  );
1526
1587
  this.emit("payload", this);
1527
1588
  } else if (wrappedPayload.method_end) {
1528
- // We don't need to do anything here, since we notify the client when we receive the client_end.
1529
1589
  log$2("method_end received");
1590
+ if (!this.#endEmitted) {
1591
+ this.#endEmitted = true;
1592
+ this.emit("end", this);
1593
+ } else {
1594
+ log$2("method_end: end already emitted");
1595
+ }
1530
1596
  }
1531
1597
  } catch (err) {
1532
1598
  log$2("JSON.parse failure parsing json_payload: %s", err.message);
@@ -1535,7 +1601,12 @@ class RpcInvocation extends EventEmitter__default["default"] {
1535
1601
 
1536
1602
  resolve();
1537
1603
  } else if (invoke_request.client_end) {
1538
- this.emit("end", this);
1604
+ if (!this.#endEmitted) {
1605
+ this.#endEmitted = true;
1606
+ this.emit("end", this);
1607
+ } else {
1608
+ log$2("client_end: end already emitted");
1609
+ }
1539
1610
  } else {
1540
1611
  // Do we need to support json_payload here?
1541
1612
  reject(new Error("No payload in invoke request"));
@@ -1562,10 +1633,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
1562
1633
  });
1563
1634
  }
1564
1635
 
1565
- const iv = voltClientWeb.randomBytes(16);
1636
+ const iv = randomBytes(16);
1566
1637
  if (this.#derivedKey) {
1567
1638
  // Encrypt the response using the shared key and iv.
1568
- responsePayload = voltClientWeb.aesEncrypt(this.#derivedKey, iv, responsePayload);
1639
+ responsePayload = aesEncrypt(this.#derivedKey, iv, responsePayload);
1569
1640
  }
1570
1641
 
1571
1642
  const invokeResponse = {
@@ -1605,10 +1676,10 @@ class RpcInvocation extends EventEmitter__default["default"] {
1605
1676
  endPayload = tunnelMethod.requestSerialize(endPayload);
1606
1677
  }
1607
1678
 
1608
- const iv = voltClientWeb.randomBytes(16);
1679
+ const iv = randomBytes(16);
1609
1680
  if (this.#derivedKey) {
1610
1681
  // Encrypt the response using the shared key and iv.
1611
- endPayload = voltClientWeb.aesEncrypt(this.#derivedKey, iv, endPayload);
1682
+ endPayload = aesEncrypt(this.#derivedKey, iv, endPayload);
1612
1683
  }
1613
1684
 
1614
1685
  const invokeResponse = {
@@ -1631,6 +1702,8 @@ class RpcInvocation extends EventEmitter__default["default"] {
1631
1702
 
1632
1703
  /* eslint-disable no-underscore-dangle */
1633
1704
 
1705
+ const { publicKeyToPem, removeCarriageReturn, signBase64 } = js.voltUtils;
1706
+
1634
1707
  const { filter, pick } = lodash__default["default"];
1635
1708
 
1636
1709
  const log$1 = debug__default["default"]("volt-client-grpc:volt-client-internal");
@@ -1763,8 +1836,8 @@ async function authenticateInternal(
1763
1836
  }
1764
1837
 
1765
1838
  const keyPair = this._credential.getKey();
1766
- const publicKeyPem = voltClientWeb.removeCarriageReturn(
1767
- voltClientWeb.publicKeyToPem(keyPair.publicKey)
1839
+ const publicKeyPem = removeCarriageReturn(
1840
+ publicKeyToPem(keyPair.publicKey)
1768
1841
  );
1769
1842
 
1770
1843
  if (!this._credential.cache.bindIp) {
@@ -1782,8 +1855,8 @@ async function authenticateInternal(
1782
1855
  };
1783
1856
 
1784
1857
  if (this._voltConfig.challenge_code) {
1785
- authenticateRequest.challenge = voltClientWeb.signBase64(
1786
- keyPair.privateKey,
1858
+ authenticateRequest.challenge = signBase64(
1859
+ this._credential.cache.key,
1787
1860
  this._voltConfig.challenge_code
1788
1861
  );
1789
1862
  } else {
@@ -1813,16 +1886,18 @@ async function authenticateInternal(
1813
1886
  // This is because the DID document is signed and the signature
1814
1887
  // is over the entire document.
1815
1888
  const didDocument = {
1816
- "@context": "https://www.w3.org/ns/did/v1",
1889
+ "@context": [
1890
+ "https://www.w3.org/ns/did/v1",
1891
+ "https://tdxvolt.com/ns/did/v1"
1892
+ ],
1817
1893
  authentication: [`${did}#key-1`],
1818
1894
  controller: did,
1819
- description: this._config.client_name,
1820
1895
  id: did,
1821
1896
  verificationMethod: [
1822
1897
  {
1823
1898
  id: `${did}#key-1`,
1824
1899
  publicKeyPem: publicKeyPem,
1825
- type: "Ed25519VerificationKey2018"
1900
+ type: "Ed25519Signature2018"
1826
1901
  }
1827
1902
  ]
1828
1903
  };
@@ -1832,8 +1907,8 @@ async function authenticateInternal(
1832
1907
 
1833
1908
  // Now sign the entire DID document, including the proof and set it in the
1834
1909
  // bind request. This is required by the Volt to verify that we have the private key for the DID.
1835
- authenticateRequest.did_document_signature = voltClientWeb.signBase64(
1836
- keyPair.privateKey,
1910
+ authenticateRequest.did_document_signature = signBase64(
1911
+ this._credential.cache.key,
1837
1912
  authenticateRequest.did_document
1838
1913
  );
1839
1914
 
@@ -1871,7 +1946,7 @@ async function authenticateInternal(
1871
1946
 
1872
1947
  return decision === "POLICY_DECISION_PERMIT";
1873
1948
  } catch (err) {
1874
- log$1("failure binding to Volt [%s]", err.message);
1949
+ log$1("failure authenticating with Volt [%s]", err.message);
1875
1950
  throw err;
1876
1951
  }
1877
1952
  }
@@ -1887,15 +1962,7 @@ function connectInternal(helloPayload) {
1887
1962
  this._connected = false;
1888
1963
  this._session = null;
1889
1964
 
1890
- if (this._cachedClient) {
1891
- this._grpc.closeClient(this._cachedClient);
1892
- this._cachedClient = null;
1893
- }
1894
-
1895
- if (this._cachedRemoteClient) {
1896
- this._grpc.closeClient(this._cachedRemoteClient);
1897
- this._cachedRemoteClient = null;
1898
- }
1965
+ this.close();
1899
1966
  };
1900
1967
 
1901
1968
  this._voltConnection = new VoltConnection(this, this._grpc);
@@ -1984,7 +2051,7 @@ function connectInternal(helloPayload) {
1984
2051
 
1985
2052
  function getVoltAPIClientInternal() {
1986
2053
  if (!this._cachedClient) {
1987
- const serviceAddress = this.isRemote
2054
+ const serviceAddress = this.isRelayed
1988
2055
  ? this._voltConfig.relay.address
1989
2056
  : this._voltConfig.address;
1990
2057
  log$1("creating cached VoltAPI service client on %s", serviceAddress);
@@ -1999,7 +2066,7 @@ function getVoltAPIClientInternal() {
1999
2066
  serviceDescriptors,
2000
2067
  serviceAddress,
2001
2068
  this._credential,
2002
- this.isRemote && !this.isVoltRelay,
2069
+ this.isRelayed,
2003
2070
  this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
2004
2071
  this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
2005
2072
  );
@@ -2010,7 +2077,7 @@ function getVoltAPIClientInternal() {
2010
2077
 
2011
2078
  function getAPIClientInternal(service) {
2012
2079
  if (!this._cachedService[service.id]) {
2013
- const serviceAddress = this.isRemote
2080
+ const serviceAddress = this.isRelayed
2014
2081
  ? this._voltConfig.relay.address
2015
2082
  : service.service_description.host_address;
2016
2083
 
@@ -2033,7 +2100,7 @@ function getAPIClientInternal(service) {
2033
2100
  serviceDescriptors,
2034
2101
  serviceAddress,
2035
2102
  this._credential,
2036
- this.isRemote && !this.isVoltRelay,
2103
+ this.isRelayed,
2037
2104
  this._voltConfig?.relay?.cloud ? this._voltConfig.id : "",
2038
2105
  this._voltConfig?.relay?.cloud ? this._voltConfig.id : ""
2039
2106
  );
@@ -2128,9 +2195,9 @@ async function fetchVoltConfig(discovery_url) {
2128
2195
  }
2129
2196
  }
2130
2197
 
2131
- async function fetchVoltConfigFromDID(volt_did) {
2198
+ async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
2132
2199
  try {
2133
- const didResolution = getDIDResolutionURL(volt_did);
2200
+ const didResolution = getDIDResolutionURL(volt_did, registryUrl);
2134
2201
  if (!didResolution) {
2135
2202
  throw new Error(`Invalid Volt DID: ${volt_did}`);
2136
2203
  }
@@ -2149,6 +2216,8 @@ async function fetchVoltConfigFromDID(volt_did) {
2149
2216
  );
2150
2217
  }
2151
2218
 
2219
+ log$1("resolved DID from %s", didResolution);
2220
+
2152
2221
  const serviceEndpoint = voltConfigServices[0].serviceEndpoint;
2153
2222
  return await fetchVoltConfig.call(this, serviceEndpoint);
2154
2223
  } catch (err) {
@@ -2158,6 +2227,25 @@ async function fetchVoltConfigFromDID(volt_did) {
2158
2227
  }
2159
2228
  }
2160
2229
 
2230
+ async function fetchVoltConfigFromDID(
2231
+ volt_did,
2232
+ registryList = [constants.defaultDIDHostName]
2233
+ ) {
2234
+ for (let registryUrl of registryList) {
2235
+ try {
2236
+ return await fetchVoltConfigFromDIDInternal.call(
2237
+ this,
2238
+ volt_did,
2239
+ registryUrl
2240
+ );
2241
+ } catch (err) {
2242
+ log$1("Failed to fetch Volt config from %s: %s", registryUrl, err.message);
2243
+ }
2244
+ }
2245
+
2246
+ throw new Error("Failed to fetch Volt config from any registry");
2247
+ }
2248
+
2161
2249
  const { readFile } = fs__default["default"].promises;
2162
2250
  const log = debug__default["default"]("volt-client-grpc:volt-client");
2163
2251
 
@@ -2173,7 +2261,6 @@ class VoltClient extends EventEmitter__default["default"] {
2173
2261
  }
2174
2262
  this._grpc = grpc;
2175
2263
  this._cachedClient = null;
2176
- this._cachedRemoteClient = null;
2177
2264
  this._session = null;
2178
2265
  this._config = null;
2179
2266
  this._voltConfig = null;
@@ -2198,12 +2285,36 @@ class VoltClient extends EventEmitter__default["default"] {
2198
2285
  return this._voltConfig;
2199
2286
  }
2200
2287
 
2288
+ get connection() {
2289
+ return this._voltConnection;
2290
+ }
2291
+
2292
+ close() {
2293
+ if (this._cachedClient) {
2294
+ this._grpc.closeClient(this._cachedClient);
2295
+ this._cachedClient = null;
2296
+ }
2297
+
2298
+ for (let serviceKey in Object.keys(this._cachedService)) {
2299
+ if (this._cachedService[serviceKey]) {
2300
+ this._grpc.closeClient(this._cachedService[serviceKey]);
2301
+ }
2302
+ }
2303
+
2304
+ this._cachedService = {};
2305
+ }
2306
+
2201
2307
  /**
2202
2308
  * Initialises a binding and connection to the volt.
2203
2309
  * @param {string} [config] - the location of the Volt configuration file, or a configuration object
2204
2310
  * @param {object} [extras] - additional configuration properties
2205
2311
  */
2206
- async initialise(config, extras = {}) {
2312
+ async initialise(
2313
+ config,
2314
+ extras = {},
2315
+ ownDID = false,
2316
+ didRegistryList = undefined
2317
+ ) {
2207
2318
  try {
2208
2319
  if (!config) {
2209
2320
  throw new Error(
@@ -2268,7 +2379,15 @@ class VoltClient extends EventEmitter__default["default"] {
2268
2379
  }
2269
2380
 
2270
2381
  if (voltDID) {
2271
- const didConfig = await fetchVoltConfigFromDID.call(this, voltDID);
2382
+ const didConfig = await fetchVoltConfigFromDID.call(
2383
+ this,
2384
+ voltDID,
2385
+ didRegistryList
2386
+ );
2387
+
2388
+ // Remove the relay list from the DID config, as it would overwrite the relay in the supplied config.
2389
+ delete didConfig.relay;
2390
+
2272
2391
  this._config = { ...this._config, volt: didConfig };
2273
2392
  log("resolved config from DID: %s", JSON.stringify(didConfig, null, 2));
2274
2393
  } else if (voltHttpAddress && !this._config?.volt?.id) {
@@ -2298,7 +2417,7 @@ class VoltClient extends EventEmitter__default["default"] {
2298
2417
 
2299
2418
  await this._credential.initialise();
2300
2419
 
2301
- if (!this.isRemote) {
2420
+ if (!this.isRelayed) {
2302
2421
  // If we're not connecting via a Relay, we must have the address and CA.
2303
2422
  if (
2304
2423
  !this._voltConfig.address ||
@@ -2321,7 +2440,7 @@ class VoltClient extends EventEmitter__default["default"] {
2321
2440
  } else {
2322
2441
  // No certificate present in the cache yet => we need to authenticate.
2323
2442
  try {
2324
- isBound = await authenticateInternal.call(this);
2443
+ isBound = await authenticateInternal.call(this, false, ownDID);
2325
2444
  } catch (bindErr) {
2326
2445
  if (bindErr.message === "invalid arguments") {
2327
2446
  // This is usually the result of a missing challenge signature or credential.
@@ -2338,7 +2457,7 @@ class VoltClient extends EventEmitter__default["default"] {
2338
2457
  throw new Error("Volt authentication failed");
2339
2458
  } else {
2340
2459
  // Perist the configuration.
2341
- this._config = this._credential.saveCache();
2460
+ this._credential.saveCache();
2342
2461
  }
2343
2462
 
2344
2463
  return Promise.resolve(this._config);
@@ -2389,7 +2508,7 @@ class VoltClient extends EventEmitter__default["default"] {
2389
2508
  });
2390
2509
  }
2391
2510
 
2392
- if (this.isRemote) {
2511
+ if (this.isRelayed) {
2393
2512
  if (!this._voltConfig?.relay?.address) {
2394
2513
  throw new Error(
2395
2514
  "Remote connection enabled but no Relay address - have you called start()?"
@@ -2416,14 +2535,10 @@ class VoltClient extends EventEmitter__default["default"] {
2416
2535
  }
2417
2536
  }
2418
2537
 
2419
- get isRemote() {
2538
+ get isRelayed() {
2420
2539
  return !!(this._voltConfig?.relay && this._voltConfig.id);
2421
2540
  }
2422
2541
 
2423
- get isVoltRelay() {
2424
- return this.isRemote && !this._voltConfig?.relay.cloud;
2425
- }
2426
-
2427
2542
  connect(helloPayload) {
2428
2543
  return connectInternal.call(this, helloPayload);
2429
2544
  }
@@ -2753,6 +2868,9 @@ class VoltClient extends EventEmitter__default["default"] {
2753
2868
  */
2754
2869
  SqlExecuteJSON(request) {
2755
2870
  return new Promise((resolve, reject) => {
2871
+ if (!request.start) {
2872
+ request = { start: request };
2873
+ }
2756
2874
  const call = this.SqlExecute(request);
2757
2875
 
2758
2876
  let header;