@tdxvolt/volt-client-grpc 0.18.10 → 0.19.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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.18.10",
6
+ "version": "0.19.1",
7
7
  "description": "tdx Volt library for nodejs clients",
8
8
  "type": "module",
9
9
  "exports": {
@@ -37,7 +37,7 @@
37
37
  "author": "toby.ealden@gmail.com",
38
38
  "license": "ISC",
39
39
  "dependencies": {
40
- "@tdxvolt/volt-client-web": "^0.18.2",
40
+ "@tdxvolt/volt-client-web": "^0.19.1",
41
41
  "builtin-modules": "^3.3.0",
42
42
  "debug": "^4.1.1",
43
43
  "ip": "^1.1.5",
@@ -47,4 +47,4 @@
47
47
  "protobufjs": "^7.4.0",
48
48
  "uuid": "^8.1.0"
49
49
  }
50
- }
50
+ }
package/src/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const constants = {
1
+ const _constants = {
2
2
  authTokenName: "volt-token",
3
3
  defaultDIDHostName: "coreid.com",
4
4
  didServiceType: {
@@ -19,5 +19,14 @@ export const constants = {
19
19
  terminalAPI: "tdx.volt_api.volt.v1.TerminalAPI",
20
20
  voltAPI: "tdx.volt_api.volt.v1.VoltAPI",
21
21
  wireAPI: "tdx.volt_api.volt.v1.WireAPI"
22
- }
22
+ },
23
+ voltDIDPrefix: "did:volt:"
23
24
  };
25
+
26
+ _constants.defaultRegistryList = [
27
+ _constants.defaultDIDHostName,
28
+ "https://tdxvolt.com",
29
+ "https://tdxid.com"
30
+ ];
31
+
32
+ export const constants = _constants;
package/src/index.js CHANGED
@@ -1,7 +1,8 @@
1
- export {constants} from "./constants.js";
1
+ export { SyncProvider } from "@tdxvolt/volt-client-web";
2
+ export { v4 as generateId } from "uuid";
3
+ export { constants } from "./constants.js";
2
4
  export * as grpcUtils from "./grpc-utils.js";
5
+ export * as protoUtils from "./proto-utils.js";
3
6
  export * as utils from "./utils.js";
4
- export {VoltClient} from "./volt-client.js";
7
+ export { VoltClient } from "./volt-client.js";
5
8
  export * from "./volt-credential.js";
6
- export * as protoUtils from "./proto-utils.js";
7
- export {v4 as generateId} from "uuid";
@@ -105,30 +105,6 @@ export async function authenticateInternal(
105
105
  ownDID = false
106
106
  ) {
107
107
  try {
108
- // Check if we need to resolve a Relay volt.
109
- if (
110
- typeof this._voltConfig?.relay === "string" ||
111
- this._voltConfig?.relay?.http_address
112
- ) {
113
- const relayURL =
114
- this._voltConfig.relay?.http_address || this._voltConfig.relay;
115
- log("attempting to retrieve Relay information from %s", relayURL);
116
- this._voltConfig.relay = await fetchVoltConfig.call(
117
- this,
118
- `${relayURL}/discover`
119
- );
120
-
121
- if (this._voltConfig.relay.ca_pem) {
122
- log(
123
- "Auto-fetched Relay CA %s, remote address %s",
124
- this._voltConfig.relay.ca_pem,
125
- this._voltConfig.relay.address
126
- );
127
- } else {
128
- throw new Error("Unable to fetch Relay CA - cannot securely connect.");
129
- }
130
- }
131
-
132
108
  if (!this._credential.cache.ca) {
133
109
  this._credential.cache.ca = this._voltConfig.ca_pem;
134
110
  }
@@ -458,18 +434,18 @@ export function streamingCallInternal(methodType, method, request, service) {
458
434
 
459
435
  export async function fetchVoltConfig(discovery_url) {
460
436
  try {
461
- const response = await fetch(discovery_url, {
462
- headers: { Accept: "application/json" }
463
- });
437
+ const response = await fetch(discovery_url);
464
438
 
465
439
  if (!response.ok) {
466
- throw new Error(`HTTP error! Status: ${response.status}`);
440
+ log("fetchVoltConfig - error [%s]", response.status);
441
+ return null;
467
442
  }
468
443
 
469
444
  const fullVoltConfig = await response.json();
470
445
 
471
446
  if (!fullVoltConfig || typeof fullVoltConfig !== "object") {
472
- throw new Error(`invalid config resolved from: ${discovery_url}`);
447
+ log("fetchVoltConfig - invalid config resolved from: %s", discovery_url);
448
+ return null;
473
449
  }
474
450
 
475
451
  const voltConfig = pick(
@@ -484,11 +460,12 @@ export async function fetchVoltConfig(discovery_url) {
484
460
  "relay"
485
461
  );
486
462
 
463
+ log("fetchVoltConfig from %s", discovery_url);
464
+
487
465
  return voltConfig;
488
466
  } catch (err) {
489
- throw new Error(
490
- `Failure loading config from ${discovery_url}: ${err.message}`
491
- );
467
+ log("fetchVoltConfig - %s error [%s]", discovery_url, err.message);
468
+ return null;
492
469
  }
493
470
  }
494
471
 
@@ -499,12 +476,10 @@ async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
499
476
  throw new Error(`Invalid Volt DID: ${volt_did}`);
500
477
  }
501
478
 
502
- const response = await fetch(didResolution, {
503
- headers: { Accept: "application/json" }
504
- });
479
+ const response = await fetch(didResolution);
505
480
 
506
481
  if (!response.ok) {
507
- throw new Error(`HTTP error! Status: ${response.status}`);
482
+ throw new Error(`HTTP error, status: ${response.status}`);
508
483
  }
509
484
 
510
485
  const didDocument = await response.json();
@@ -523,7 +498,12 @@ async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
523
498
  log("resolved DID from %s", didResolution);
524
499
 
525
500
  const serviceEndpoint = voltConfigServices[0].serviceEndpoint;
526
- return await fetchVoltConfig.call(this, serviceEndpoint);
501
+ const voltConfig = await fetchVoltConfig.call(this, serviceEndpoint);
502
+ if (!voltConfig) {
503
+ throw new Error(`failed to resolve Volt config from ${serviceEndpoint}`);
504
+ }
505
+
506
+ return voltConfig;
527
507
  } catch (err) {
528
508
  throw new Error(
529
509
  `Failure fetching Volt config from DID document ${volt_did}: ${err.message}`
@@ -531,25 +511,128 @@ async function fetchVoltConfigFromDIDInternal(volt_did, registryUrl) {
531
511
  }
532
512
  }
533
513
 
534
- export async function fetchVoltConfigFromDID(
535
- volt_did,
536
- registryList = [constants.defaultDIDHostName]
537
- ) {
514
+ export async function fetchVoltConfigFromDID(volt_did, registryListIn) {
515
+ let registryList;
516
+ if (!registryListIn) {
517
+ // If no registry list is provided, use the default registry list.
518
+ registryList = constants.defaultRegistryList;
519
+ } else {
520
+ // If a registry list is provided, merge it with the default registry list.
521
+ registryList = Array.from(
522
+ new Set(registryListIn.concat(constants.defaultRegistryList))
523
+ );
524
+ }
525
+
526
+ let voltConfig;
538
527
  for (let registryUrl of registryList) {
539
528
  try {
540
- return await fetchVoltConfigFromDIDInternal.call(
529
+ voltConfig = await fetchVoltConfigFromDIDInternal.call(
541
530
  this,
542
531
  volt_did,
543
532
  registryUrl
544
533
  );
534
+
535
+ // If we've found a config, break out of the loop.
536
+ break;
537
+ } catch (err) {
538
+ log("unable to fetch Volt config from %s: %s", registryUrl, err.message);
539
+ }
540
+ }
541
+
542
+ if (!voltConfig) {
543
+ log("failed to fetch Volt config for %s from any registry", volt_did);
544
+ }
545
+
546
+ return voltConfig;
547
+ }
548
+
549
+ export async function resolveVoltConfig(cfg, didRegistryList) {
550
+ // Start by resolving the relay if one is specified.
551
+ let relay = cfg?.relay?.http_address || cfg?.relay;
552
+ if (relay) {
553
+ relay = await resolveVoltConfig.call(this, relay, didRegistryList);
554
+ }
555
+
556
+ let voltDID = "";
557
+ let voltHttpAddress = "";
558
+
559
+ if (typeof cfg === "string") {
560
+ // If the configuration is a string, determine if it is a DID or HTTP address.
561
+ if (cfg.indexOf("did:") === 0) {
562
+ voltDID = cfg;
563
+ } else {
564
+ voltHttpAddress = cfg;
565
+ }
566
+ cfg = {};
567
+ } else if (typeof cfg === "object") {
568
+ voltDID = cfg.id;
569
+ voltHttpAddress = cfg.http_address;
570
+ } else {
571
+ throw new Error("configuration is missing the 'volt' object");
572
+ }
573
+
574
+ let resolvedConfig;
575
+
576
+ if (relay) {
577
+ if (!voltDID) {
578
+ throw new Error("relay specified but no Volt DID provided");
579
+ }
580
+
581
+ // Build the sub-domain URL for the Volt discovery service by inserting the volt DID into the relay URL.
582
+ const relayURL = relay.http_address;
583
+ const relayParts = relayURL.split("://");
584
+ const subdomain = voltDID.substring(constants.voltDIDPrefix.length);
585
+ voltHttpAddress = `${relayParts[0]}://${subdomain}.${relayParts[1]}`;
586
+ } else if (voltDID) {
587
+ resolvedConfig = await fetchVoltConfigFromDID.call(
588
+ this,
589
+ voltDID,
590
+ didRegistryList
591
+ );
592
+ }
593
+
594
+ if (!resolvedConfig && voltHttpAddress) {
595
+ try {
596
+ resolvedConfig = await fetchVoltConfig.call(
597
+ this,
598
+ `${voltHttpAddress}/discover`
599
+ );
600
+
601
+ // Update the http address in the resolved config to the one we used to
602
+ // fetch it, since we may have used the relay rather than local address.
603
+ resolvedConfig.http_address = voltHttpAddress;
545
604
  } catch (err) {
546
- log("Failed to fetch Volt config from %s: %s", registryUrl, err.message);
605
+ log(
606
+ "failed to resolve Volt configuration %s [%s]",
607
+ voltHttpAddress,
608
+ err.message
609
+ );
547
610
  }
548
611
  }
549
612
 
550
- throw new Error(
551
- `Failed to fetch Volt config from any of these registries: ${registryList.join(
552
- ", "
553
- )}`
554
- );
613
+ if (!resolvedConfig) {
614
+ if (cfg.address && cfg.ca_pem) {
615
+ log(
616
+ "unable to resolve %s / %s, using existing configuration",
617
+ voltDID,
618
+ voltHttpAddress
619
+ );
620
+ } else {
621
+ throw new Error(
622
+ `failed to resolve Volt ${voltDID} / ${voltHttpAddress} and no existing configuration`
623
+ );
624
+ }
625
+ } else {
626
+ log("resolved config from: %s", voltDID || voltHttpAddress);
627
+ log(JSON.stringify(resolvedConfig, null, 2));
628
+
629
+ cfg = {
630
+ ...cfg,
631
+ ...resolvedConfig
632
+ };
633
+ }
634
+
635
+ cfg.relay = relay;
636
+
637
+ return cfg;
555
638
  }
@@ -6,9 +6,8 @@ import GRPCCall from "./grpc-call.js";
6
6
  import {
7
7
  authenticateInternal,
8
8
  connectInternal,
9
- fetchVoltConfig,
10
- fetchVoltConfigFromDID,
11
9
  getVoltAPIClientInternal,
10
+ resolveVoltConfig,
12
11
  streamingCallInternal,
13
12
  unaryCallInternal
14
13
  } from "./volt-client-internal.js";
@@ -74,19 +73,22 @@ export class VoltClient extends EventEmitter {
74
73
 
75
74
  /**
76
75
  * Initialises a binding and connection to the volt.
77
- * @param {string} [config] - the location of the Volt configuration file, or a configuration object
78
- * @param {object} [extras] - additional configuration properties
76
+ * @param {string | object} [config] - the location of the Volt configuration
77
+ * file, or a configuration object
78
+ * @param {object} [options] - initialisation options
79
+ * @param {string[]} [options.didRegistryList] - list of DID registry URLs to use for
80
+ * resolving DIDs
81
+ * @param {object} [options.extraConfig] - additional configuration to be merged with the
82
+ * configuration from the config file.
83
+ * @param {boolean} [options.ownDID] - whether the Volt should manage the DID - set to
84
+ * true if you want to manage the DID yourself
79
85
  */
80
- async initialise(
81
- config,
82
- extras = {},
83
- ownDID = false,
84
- didRegistryList = undefined
85
- ) {
86
+ async initialise(config, options = {}) {
87
+ const { ownDID, didRegistryList, extraConfig } = options;
86
88
  try {
87
89
  if (!config) {
88
90
  throw new Error(
89
- "configPath argument is required to be a non-empty string"
91
+ "config argument is required to be a non-empty string or JSON object"
90
92
  );
91
93
  }
92
94
 
@@ -119,7 +121,8 @@ export class VoltClient extends EventEmitter {
119
121
  throw new Error("config argument is required to be an object");
120
122
  }
121
123
 
122
- this._config = { ...extras, ...configJSON };
124
+ // Merge any extra configuration supplied, preferring that loaded from file.
125
+ this._config = { ...extraConfig, ...configJSON };
123
126
 
124
127
  if (
125
128
  !this._config.client_name ||
@@ -128,52 +131,13 @@ export class VoltClient extends EventEmitter {
128
131
  throw new Error("client_name property required in config");
129
132
  }
130
133
 
131
- let voltDID = "";
132
- let voltHttpAddress = "";
133
- if (typeof this._config.volt === "string") {
134
- if (this._config.volt.indexOf("did:") === 0) {
135
- voltDID = this._config.volt;
136
- } else {
137
- voltHttpAddress = this._config.volt;
138
- }
139
- delete this._config.volt;
140
- } else if (typeof this._config.volt !== "object") {
141
- throw new Error("configuration is missing the 'volt' object");
142
- } else {
143
- voltDID = this._config.volt.did;
144
- voltHttpAddress = this._config.volt.http_address;
145
- }
146
-
147
- if (voltDID) {
148
- const didConfig = await fetchVoltConfigFromDID.call(
149
- this,
150
- voltDID,
151
- didRegistryList
152
- );
153
-
154
- // Remove the relay list from the DID config, as it would overwrite the relay in the supplied config.
155
- delete didConfig.relay;
156
-
157
- this._config = { ...this._config, volt: didConfig };
158
- log("resolved config from DID: %s", JSON.stringify(didConfig, null, 2));
159
- } else if (voltHttpAddress && !this._config?.volt?.id) {
160
- const discoConfig = await fetchVoltConfig.call(
161
- this,
162
- `${voltHttpAddress}/discover`
163
- );
164
- this._config = {
165
- ...this._config,
166
- volt: { ...this._config.volt, ...discoConfig }
167
- };
168
- }
134
+ this._config.volt = await resolveVoltConfig.call(
135
+ this,
136
+ this._config.volt,
137
+ didRegistryList
138
+ );
169
139
 
170
140
  this._voltConfig = this._config.volt;
171
- if (voltDID) {
172
- this._voltConfig.did = voltDID;
173
- }
174
- if (voltHttpAddress) {
175
- this._voltConfig.http_address = voltHttpAddress;
176
- }
177
141
 
178
142
  if (!this._voltConfig.id || typeof this._voltConfig.id !== "string") {
179
143
  throw new Error("'id' property is missing in Volt configuration");
@@ -228,13 +192,14 @@ export class VoltClient extends EventEmitter {
228
192
 
229
193
  return Promise.resolve(this._config);
230
194
  } catch (err) {
231
- log("Failure starting Volt client [%s]", err.message);
195
+ log("failure starting Volt client [%s]", err.message);
232
196
  throw err;
233
197
  }
234
198
  }
235
199
 
236
- initialiseAndConnect(configPath, helloPayload = undefined, extras = {}) {
237
- return this.initialise(configPath, extras)
200
+ initialiseAndConnect(configPath, options) {
201
+ const helloPayload = options?.helloPayload;
202
+ return this.initialise(configPath, options)
238
203
  .then(() => {
239
204
  return connectInternal.call(this, helloPayload);
240
205
  })
@@ -2747,6 +2747,7 @@ message InvokeResponse {
2747
2747
  // The invocation id to match the originating request.
2748
2748
  uint64 invoke_id = 1;
2749
2749
 
2750
+ // Key exchange details for the response payload encryption. Only necessary for the first response.
2750
2751
  InvokeRequestKeyExchange key_exchange = 2;
2751
2752
 
2752
2753
  // The initialisation vector for the response payload encryption. This will be a random 16 byte value, that is different for each response.