@hiero-ledger/sdk 2.76.0 → 2.77.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 (75) hide show
  1. package/dist/umd.js +426 -82
  2. package/dist/umd.min.js +14 -14
  3. package/lib/Executable.cjs +13 -3
  4. package/lib/Executable.js +1 -1
  5. package/lib/Executable.js.map +1 -1
  6. package/lib/channel/Channel.cjs +25 -1
  7. package/lib/channel/Channel.d.ts +20 -0
  8. package/lib/channel/Channel.js +1 -1
  9. package/lib/channel/Channel.js.map +1 -1
  10. package/lib/channel/NativeChannel.cjs +96 -2
  11. package/lib/channel/NativeChannel.d.ts +21 -1
  12. package/lib/channel/NativeChannel.js +1 -1
  13. package/lib/channel/NativeChannel.js.map +1 -1
  14. package/lib/channel/NodeChannel.cjs +4 -5
  15. package/lib/channel/NodeChannel.d.ts +2 -3
  16. package/lib/channel/NodeChannel.js +1 -1
  17. package/lib/channel/NodeChannel.js.map +1 -1
  18. package/lib/channel/WebChannel.cjs +163 -13
  19. package/lib/channel/WebChannel.d.ts +51 -1
  20. package/lib/channel/WebChannel.js +1 -1
  21. package/lib/channel/WebChannel.js.map +1 -1
  22. package/lib/client/Client.cjs +62 -5
  23. package/lib/client/Client.d.ts +26 -3
  24. package/lib/client/Client.js +1 -1
  25. package/lib/client/Client.js.map +1 -1
  26. package/lib/client/NativeClient.cjs +1 -1
  27. package/lib/client/NativeClient.js +1 -1
  28. package/lib/client/NativeClient.js.map +1 -1
  29. package/lib/client/NodeClient.cjs +7 -6
  30. package/lib/client/NodeClient.d.ts +3 -3
  31. package/lib/client/NodeClient.js +1 -1
  32. package/lib/client/NodeClient.js.map +1 -1
  33. package/lib/client/WebClient.cjs +55 -27
  34. package/lib/client/WebClient.d.ts +6 -0
  35. package/lib/client/WebClient.js +1 -1
  36. package/lib/client/WebClient.js.map +1 -1
  37. package/lib/client/addressbooks/mainnet.cjs +1 -1
  38. package/lib/client/addressbooks/mainnet.d.ts +1 -1
  39. package/lib/client/addressbooks/mainnet.js +1 -1
  40. package/lib/client/addressbooks/mainnet.js.map +1 -1
  41. package/lib/client/addressbooks/previewnet.cjs +1 -1
  42. package/lib/client/addressbooks/previewnet.d.ts +1 -1
  43. package/lib/client/addressbooks/previewnet.js +1 -1
  44. package/lib/client/addressbooks/previewnet.js.map +1 -1
  45. package/lib/client/addressbooks/testnet.cjs +1 -1
  46. package/lib/client/addressbooks/testnet.d.ts +1 -1
  47. package/lib/client/addressbooks/testnet.js +1 -1
  48. package/lib/client/addressbooks/testnet.js.map +1 -1
  49. package/lib/constants/ClientConstants.cjs +17 -1
  50. package/lib/constants/ClientConstants.d.ts +14 -0
  51. package/lib/constants/ClientConstants.js +1 -1
  52. package/lib/constants/ClientConstants.js.map +1 -1
  53. package/lib/network/AddressBookQuery.cjs +0 -4
  54. package/lib/network/AddressBookQuery.js +1 -1
  55. package/lib/network/AddressBookQuery.js.map +1 -1
  56. package/lib/network/AddressBookQueryWeb.cjs +1 -5
  57. package/lib/network/AddressBookQueryWeb.js +1 -1
  58. package/lib/network/AddressBookQueryWeb.js.map +1 -1
  59. package/lib/version.js +1 -1
  60. package/package.json +7 -7
  61. package/src/Executable.js +18 -2
  62. package/src/channel/Channel.js +25 -1
  63. package/src/channel/NativeChannel.js +111 -2
  64. package/src/channel/NodeChannel.js +4 -7
  65. package/src/channel/WebChannel.js +189 -21
  66. package/src/client/Client.js +79 -5
  67. package/src/client/NativeClient.js +1 -1
  68. package/src/client/NodeClient.js +7 -6
  69. package/src/client/WebClient.js +64 -31
  70. package/src/client/addressbooks/mainnet.js +1 -1
  71. package/src/client/addressbooks/previewnet.js +1 -1
  72. package/src/client/addressbooks/testnet.js +1 -1
  73. package/src/constants/ClientConstants.js +16 -0
  74. package/src/network/AddressBookQuery.js +0 -7
  75. package/src/network/AddressBookQueryWeb.js +1 -8
@@ -439,7 +439,7 @@ class Executable {
439
439
  */
440
440
  _shouldRetryExceptionally(error) {
441
441
  if (error instanceof _GrpcServiceError.default) {
442
- return error.status._code === _GrpcStatus.default.Timeout._code || error.status._code === _GrpcStatus.default.Unavailable._code || error.status._code === _GrpcStatus.default.ResourceExhausted._code || error.status._code === _GrpcStatus.default.GrpcWeb._code || error.status._code === _GrpcStatus.default.Internal._code && RST_STREAM.test(error.message);
442
+ return error.status._code === _GrpcStatus.default.Timeout._code || error.status._code === _GrpcStatus.default.DeadlineExceeded._code || error.status._code === _GrpcStatus.default.Unavailable._code || error.status._code === _GrpcStatus.default.ResourceExhausted._code || error.status._code === _GrpcStatus.default.GrpcWeb._code || error.status._code === _GrpcStatus.default.Internal._code && RST_STREAM.test(error.message);
443
443
  } else {
444
444
  // if we get to the 'else' statement, the 'error' is instanceof 'HttpError'
445
445
  // and in this case, we have to retry always
@@ -515,6 +515,11 @@ class Executable {
515
515
  this._requestTimeout = requestTimeout != null ? requestTimeout : client.requestTimeout;
516
516
  }
517
517
 
518
+ // If the grpc deadline is not set on the request, use the default value from client
519
+ if (this._grpcDeadline == null) {
520
+ this._grpcDeadline = client.grpcDeadline;
521
+ }
522
+
518
523
  // Some request need to perform additional requests before the executing
519
524
  // such as paid queries need to fetch the cost of the query before
520
525
  // finally executing the actual query.
@@ -590,6 +595,11 @@ class Executable {
590
595
  this._logger.debug(`[${logId}] Node AccountID: ${node.accountId.toString()}, IP: ${node.address.toString()}`);
591
596
  }
592
597
  const channel = node.getChannel();
598
+
599
+ // Set the gRPC deadline on the channel if this query has a custom deadline
600
+ if (this._grpcDeadline != null) {
601
+ channel.setGrpcDeadline(this._grpcDeadline);
602
+ }
593
603
  const request = await this._makeRequestAsync();
594
604
  let response;
595
605
  if (!node.isHealthy()) {
@@ -617,14 +627,14 @@ class Executable {
617
627
  // from blocking this request
618
628
  const promises = [];
619
629
 
620
- // If a grpc deadline is est, we should race it, otherwise the only thing in the
630
+ // If a grpc deadline is set, we should race it, otherwise the only thing in the
621
631
  // list of promises will be the execution promise.
622
632
  if (this._grpcDeadline != null) {
623
633
  promises.push(
624
634
  // eslint-disable-next-line ie11/no-loop-func
625
635
  new Promise((_, reject) => setTimeout(
626
636
  // eslint-disable-next-line ie11/no-loop-func
627
- () => reject(new Error("grpc deadline exceeded")), /** @type {number=} */this._grpcDeadline)));
637
+ () => reject(new _GrpcServiceError.default(_GrpcStatus.default.DeadlineExceeded)), /** @type {number=} */this._grpcDeadline)));
628
638
  }
629
639
  if (this._logger) {
630
640
  this._logger.trace(`[${this._getLogId()}] sending protobuf ${hex.encode(this._requestToBytes(request))}`);
package/lib/Executable.js CHANGED
@@ -1,2 +1,2 @@
1
- import t from"./grpc/GrpcServiceError.js";import e from"./grpc/GrpcStatus.js";import o from"./transaction/List.js";import{encode as n}from"./encoding/hex.js";import r from"./http/HttpError.js";import s from"./Status.js";import i from"./MaxAttemptsOrTimeoutError.js";const c={Finished:"Finished",Retry:"Retry",Error:"Error"},a=/\brst[^0-9a-zA-Z]stream\b/i,h=10;class u{constructor(){this._maxAttempts=10,this._nodeAccountIds=new o,this.transactionNodeIds=[],this._signOnDemand=!1,this._minBackoff=null,this._maxBackoff=8e3,this._operator=null,this._requestTimeout=null,this._grpcDeadline=null,this._logger=null}get nodeAccountIds(){return this._nodeAccountIds.isEmpty?null:(this._nodeAccountIds.setLocked(),this._nodeAccountIds.list)}setNodeAccountIds(t){return this._nodeAccountIds.setList(t).setLocked(),this}get maxRetries(){return console.warn("Deprecated: use maxAttempts instead"),this.maxAttempts}setMaxRetries(t){return console.warn("Deprecated: use setMaxAttempts() instead"),this.setMaxAttempts(t)}get maxAttempts(){return this._maxAttempts}setMaxAttempts(t){return this._maxAttempts=t,this}get grpcDeadline(){return this._grpcDeadline}setGrpcDeadline(t){return this._grpcDeadline=t,this}setMinBackoff(t){if(null==t)throw new Error("minBackoff cannot be null.");if(null!=this._maxBackoff&&t>this._maxBackoff)throw new Error("minBackoff cannot be larger than maxBackoff.");return this._minBackoff=t,this}get minBackoff(){return this._minBackoff}setMaxBackoff(t){if(null==t)throw new Error("maxBackoff cannot be null.");if(null!=this._minBackoff&&t<this._minBackoff)throw new Error("maxBackoff cannot be smaller than minBackoff.");return this._maxBackoff=t,this}get maxBackoff(){return this._maxBackoff}_beforeExecute(t){throw new Error("not implemented")}_makeRequestAsync(){throw new Error("not implemented")}_mapStatusError(t,e,o){throw new Error("not implemented")}_mapResponse(t,e,o){throw new Error("not implemented")}_execute(t,e){throw new Error("not implemented")}_getTransactionId(){throw new Error("not implemented")}_getLogId(){throw new Error("not implemented")}_requestToBytes(t){throw new Error("not implemented")}_responseToBytes(t){throw new Error("not implemented")}_shouldRetry(t,e){throw new Error("not implemented")}_shouldRetryExceptionally(o){return!(o instanceof t)||(o.status._code===e.Timeout._code||o.status._code===e.Unavailable._code||o.status._code===e.ResourceExhausted._code||o.status._code===e.GrpcWeb._code||o.status._code===e.Internal._code&&a.test(o.message))}_setOperatorWith(t,e,o){return this._operator={transactionSigner:o,accountId:t,publicKey:e},this}async executeWithSigner(t){return t.call(this)}isBatchedAndNotBatchTransaction(){return!1}async execute(e,o){const a=null!=e.network["127.0.0.1:50211"];if(this.isBatchedAndNotBatchTransaction())throw new Error("Cannot execute batchified transaction outside of BatchTransaction");this._logger=null==this._logger?null!=e._logger?e._logger:null:this._logger,null==this._requestTimeout&&(this._requestTimeout=null!=o?o:e.requestTimeout),await this._beforeExecute(e),null==this._maxBackoff&&(this._maxBackoff=e.maxBackoff),null==this._minBackoff&&(this._minBackoff=e.minBackoff);const h=Date.now();let u=null;const m=a?1e3:e._maxAttempts??this._maxAttempts;if(this.transactionNodeIds.length){const t=this._nodeAccountIds.list.map(t=>t.toString());if(!this.transactionNodeIds.some(e=>t.includes(e))){const e=t.length>2?`${t.slice(0,2).join(", ")} ...`:t.join(", "),o=1===t.length;throw new Error(`Attempting to execute a transaction against node${o?"":"s"} ${e}, which ${o?"is":"are"} not included in the Client's node list. Please review your Client configuration.`)}}for(let o=1;o<=m;o+=1){if(null!=this._requestTimeout&&h+this._requestTimeout<=Date.now())throw new i("timeout exceeded",this._nodeAccountIds.isEmpty?"No node account ID set":this._nodeAccountIds.current.toString());let g,_;if(this._nodeAccountIds.isEmpty?(_=e._network.getNode(),g=_.accountId,this._nodeAccountIds.setList([g])):(g=this._nodeAccountIds.current,_=e._network.getNode(g)),null==_)throw new Error(`NodeAccountId not recognized: ${g.toString()}`);if(this.transactionNodeIds.length){if(!this.transactionNodeIds.includes(g.toString())){console.error(`Attempting to execute a transaction against node ${g.toString()}, which is not included in the Client's node list. Please review your Client configuration.`),this._nodeAccountIds.advance();continue}}const f=this._getLogId();this._logger&&this._logger.debug(`[${f}] Node AccountID: ${_.accountId.toString()}, IP: ${_.address.toString()}`);const p=_.getChannel(),w=await this._makeRequestAsync();let x;if(!_.isHealthy()){const t=this._nodeAccountIds.index===this._nodeAccountIds.list.length-1;if(d(w)||a){await l(a,o,this._minBackoff,this._maxBackoff);continue}if(t||this._nodeAccountIds.length<=1)throw new Error(`Network connectivity issue: All nodes are unhealthy. Original node list: ${this._nodeAccountIds.list.join(", ")}`);this._logger&&this._logger.debug(`[${f}] Node is not healthy, trying the next node.`),this._nodeAccountIds.advance();continue}this._nodeAccountIds.advance();try{const t=[];null!=this._grpcDeadline&&t.push(new Promise((t,e)=>setTimeout(()=>e(new Error("grpc deadline exceeded")),this._grpcDeadline))),this._logger&&this._logger.trace(`[${this._getLogId()}] sending protobuf ${n(this._requestToBytes(w))}`),t.push(this._execute(p,w)),x=await Promise.race(t)}catch(n){const s=t._fromResponse(n);if(u=s,this._logger&&this._logger.debug(`[${f}] received error ${JSON.stringify(s)}`),(s instanceof t||s instanceof r)&&this._shouldRetryExceptionally(s)&&o<=m){this._logger&&this._logger.debug(`[${this._getLogId()}] node with accountId: ${_.accountId.toString()} and proxy IP: ${_.address.toString()} is unhealthy`),e._network.increaseBackoff(_);continue}throw n}this._logger&&this._logger.trace(`[${this._getLogId()}] sending protobuf ${n(this._responseToBytes(x))}`),e._network.decreaseBackoff(_);const[k,A]=this._shouldRetry(w,x);switch(k.toString()!==s.Ok.toString()&&k.toString()!==s.Success.toString()&&(u=k),A){case c.Retry:await l(a,o,this._minBackoff,this._maxBackoff);continue;case c.Finished:return this._mapResponse(x,g,w);case c.Error:throw this._mapStatusError(w,x,g);default:throw new Error("(BUG) non-exhaustive switch statement for `ExecutionState`")}}throw new i(`max attempts of ${m.toString()} was reached for request with last error being: ${null!=u?u.toString():""}`,this._nodeAccountIds.current.toString())}toBytes(){throw new Error("not implemented")}setLogger(t){return this._logger=t,this}get logger(){return this._logger}}function d(t){return"object"==typeof t&&null!==t&&("transactionGetReceipt"in t||"transactionGetRecord"in t)}function l(t,e,o,n){if(t)return new Promise(t=>setTimeout(t,o));const r=Math.min(Math.floor(o*Math.pow(2,e)),n);return new Promise(t=>setTimeout(t,r))}export{h as DEFAULT_MAX_ATTEMPTS,c as ExecutionState,a as RST_STREAM,u as default};
1
+ import t from"./grpc/GrpcServiceError.js";import e from"./grpc/GrpcStatus.js";import n from"./transaction/List.js";import{encode as o}from"./encoding/hex.js";import r from"./http/HttpError.js";import s from"./Status.js";import i from"./MaxAttemptsOrTimeoutError.js";const c={Finished:"Finished",Retry:"Retry",Error:"Error"},a=/\brst[^0-9a-zA-Z]stream\b/i,h=10;class d{constructor(){this._maxAttempts=10,this._nodeAccountIds=new n,this.transactionNodeIds=[],this._signOnDemand=!1,this._minBackoff=null,this._maxBackoff=8e3,this._operator=null,this._requestTimeout=null,this._grpcDeadline=null,this._logger=null}get nodeAccountIds(){return this._nodeAccountIds.isEmpty?null:(this._nodeAccountIds.setLocked(),this._nodeAccountIds.list)}setNodeAccountIds(t){return this._nodeAccountIds.setList(t).setLocked(),this}get maxRetries(){return console.warn("Deprecated: use maxAttempts instead"),this.maxAttempts}setMaxRetries(t){return console.warn("Deprecated: use setMaxAttempts() instead"),this.setMaxAttempts(t)}get maxAttempts(){return this._maxAttempts}setMaxAttempts(t){return this._maxAttempts=t,this}get grpcDeadline(){return this._grpcDeadline}setGrpcDeadline(t){return this._grpcDeadline=t,this}setMinBackoff(t){if(null==t)throw new Error("minBackoff cannot be null.");if(null!=this._maxBackoff&&t>this._maxBackoff)throw new Error("minBackoff cannot be larger than maxBackoff.");return this._minBackoff=t,this}get minBackoff(){return this._minBackoff}setMaxBackoff(t){if(null==t)throw new Error("maxBackoff cannot be null.");if(null!=this._minBackoff&&t<this._minBackoff)throw new Error("maxBackoff cannot be smaller than minBackoff.");return this._maxBackoff=t,this}get maxBackoff(){return this._maxBackoff}_beforeExecute(t){throw new Error("not implemented")}_makeRequestAsync(){throw new Error("not implemented")}_mapStatusError(t,e,n){throw new Error("not implemented")}_mapResponse(t,e,n){throw new Error("not implemented")}_execute(t,e){throw new Error("not implemented")}_getTransactionId(){throw new Error("not implemented")}_getLogId(){throw new Error("not implemented")}_requestToBytes(t){throw new Error("not implemented")}_responseToBytes(t){throw new Error("not implemented")}_shouldRetry(t,e){throw new Error("not implemented")}_shouldRetryExceptionally(n){return!(n instanceof t)||(n.status._code===e.Timeout._code||n.status._code===e.DeadlineExceeded._code||n.status._code===e.Unavailable._code||n.status._code===e.ResourceExhausted._code||n.status._code===e.GrpcWeb._code||n.status._code===e.Internal._code&&a.test(n.message))}_setOperatorWith(t,e,n){return this._operator={transactionSigner:n,accountId:t,publicKey:e},this}async executeWithSigner(t){return t.call(this)}isBatchedAndNotBatchTransaction(){return!1}async execute(n,a){const h=null!=n.network["127.0.0.1:50211"];if(this.isBatchedAndNotBatchTransaction())throw new Error("Cannot execute batchified transaction outside of BatchTransaction");this._logger=null==this._logger?null!=n._logger?n._logger:null:this._logger,null==this._requestTimeout&&(this._requestTimeout=null!=a?a:n.requestTimeout),null==this._grpcDeadline&&(this._grpcDeadline=n.grpcDeadline),await this._beforeExecute(n),null==this._maxBackoff&&(this._maxBackoff=n.maxBackoff),null==this._minBackoff&&(this._minBackoff=n.minBackoff);const d=Date.now();let g=null;const m=h?1e3:n._maxAttempts??this._maxAttempts;if(this.transactionNodeIds.length){const t=this._nodeAccountIds.list.map(t=>t.toString());if(!this.transactionNodeIds.some(e=>t.includes(e))){const e=t.length>2?`${t.slice(0,2).join(", ")} ...`:t.join(", "),n=1===t.length;throw new Error(`Attempting to execute a transaction against node${n?"":"s"} ${e}, which ${n?"is":"are"} not included in the Client's node list. Please review your Client configuration.`)}}for(let a=1;a<=m;a+=1){if(null!=this._requestTimeout&&d+this._requestTimeout<=Date.now())throw new i("timeout exceeded",this._nodeAccountIds.isEmpty?"No node account ID set":this._nodeAccountIds.current.toString());let _,f;if(this._nodeAccountIds.isEmpty?(f=n._network.getNode(),_=f.accountId,this._nodeAccountIds.setList([_])):(_=this._nodeAccountIds.current,f=n._network.getNode(_)),null==f)throw new Error(`NodeAccountId not recognized: ${_.toString()}`);if(this.transactionNodeIds.length){if(!this.transactionNodeIds.includes(_.toString())){console.error(`Attempting to execute a transaction against node ${_.toString()}, which is not included in the Client's node list. Please review your Client configuration.`),this._nodeAccountIds.advance();continue}}const p=this._getLogId();this._logger&&this._logger.debug(`[${p}] Node AccountID: ${f.accountId.toString()}, IP: ${f.address.toString()}`);const w=f.getChannel();null!=this._grpcDeadline&&w.setGrpcDeadline(this._grpcDeadline);const x=await this._makeRequestAsync();let k;if(!f.isHealthy()){const t=this._nodeAccountIds.index===this._nodeAccountIds.list.length-1;if(u(x)||h){await l(h,a,this._minBackoff,this._maxBackoff);continue}if(t||this._nodeAccountIds.length<=1)throw new Error(`Network connectivity issue: All nodes are unhealthy. Original node list: ${this._nodeAccountIds.list.join(", ")}`);this._logger&&this._logger.debug(`[${p}] Node is not healthy, trying the next node.`),this._nodeAccountIds.advance();continue}this._nodeAccountIds.advance();try{const n=[];null!=this._grpcDeadline&&n.push(new Promise((n,o)=>setTimeout(()=>o(new t(e.DeadlineExceeded)),this._grpcDeadline))),this._logger&&this._logger.trace(`[${this._getLogId()}] sending protobuf ${o(this._requestToBytes(x))}`),n.push(this._execute(w,x)),k=await Promise.race(n)}catch(e){const o=t._fromResponse(e);if(g=o,this._logger&&this._logger.debug(`[${p}] received error ${JSON.stringify(o)}`),(o instanceof t||o instanceof r)&&this._shouldRetryExceptionally(o)&&a<=m){this._logger&&this._logger.debug(`[${this._getLogId()}] node with accountId: ${f.accountId.toString()} and proxy IP: ${f.address.toString()} is unhealthy`),n._network.increaseBackoff(f);continue}throw e}this._logger&&this._logger.trace(`[${this._getLogId()}] sending protobuf ${o(this._responseToBytes(k))}`),n._network.decreaseBackoff(f);const[A,B]=this._shouldRetry(x,k);switch(A.toString()!==s.Ok.toString()&&A.toString()!==s.Success.toString()&&(g=A),B){case c.Retry:await l(h,a,this._minBackoff,this._maxBackoff);continue;case c.Finished:return this._mapResponse(k,_,x);case c.Error:throw this._mapStatusError(x,k,_);default:throw new Error("(BUG) non-exhaustive switch statement for `ExecutionState`")}}throw new i(`max attempts of ${m.toString()} was reached for request with last error being: ${null!=g?g.toString():""}`,this._nodeAccountIds.current.toString())}toBytes(){throw new Error("not implemented")}setLogger(t){return this._logger=t,this}get logger(){return this._logger}}function u(t){return"object"==typeof t&&null!==t&&("transactionGetReceipt"in t||"transactionGetRecord"in t)}function l(t,e,n,o){if(t)return new Promise(t=>setTimeout(t,n));const r=Math.min(Math.floor(n*Math.pow(2,e)),o);return new Promise(t=>setTimeout(t,r))}export{h as DEFAULT_MAX_ATTEMPTS,c as ExecutionState,a as RST_STREAM,d as default};
2
2
  //# sourceMappingURL=Executable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Executable.js","sources":["../src/Executable.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport GrpcServiceError from \"./grpc/GrpcServiceError.js\";\nimport GrpcStatus from \"./grpc/GrpcStatus.js\";\nimport List from \"./transaction/List.js\";\nimport * as hex from \"./encoding/hex.js\";\nimport HttpError from \"./http/HttpError.js\";\nimport Status from \"./Status.js\";\nimport MaxAttemptsOrTimeoutError from \"./MaxAttemptsOrTimeoutError.js\";\n\n/**\n * @typedef {import(\"./account/AccountId.js\").default} AccountId\n * @typedef {import(\"./channel/Channel.js\").default} Channel\n * @typedef {import(\"./channel/MirrorChannel.js\").default} MirrorChannel\n * @typedef {import(\"./transaction/TransactionId.js\").default} TransactionId\n * @typedef {import(\"./client/Client.js\").ClientOperator} ClientOperator\n * @typedef {import(\"./Signer.js\").Signer} Signer\n * @typedef {import(\"./PublicKey.js\").default} PublicKey\n * @typedef {import(\"./logger/Logger.js\").default} Logger\n */\n\n/**\n * @enum {string}\n */\nexport const ExecutionState = {\n Finished: \"Finished\",\n Retry: \"Retry\",\n Error: \"Error\",\n};\n\nexport const RST_STREAM = /\\brst[^0-9a-zA-Z]stream\\b/i;\nexport const DEFAULT_MAX_ATTEMPTS = 10;\n\n/**\n * @abstract\n * @internal\n * @template RequestT\n * @template ResponseT\n * @template OutputT\n */\nexport default class Executable {\n constructor() {\n /**\n * The number of times we can retry the grpc call\n *\n * @internal\n * @type {number}\n */\n this._maxAttempts = DEFAULT_MAX_ATTEMPTS;\n\n /**\n * List of node account IDs for each transaction that has been\n * built.\n *\n * @internal\n * @type {List<AccountId>}\n */\n this._nodeAccountIds = new List();\n\n /**\n * List of the transaction node account IDs to check if\n * the node account ID of the request is in the list\n *\n * @protected\n * @type {Array<string>}\n */\n this.transactionNodeIds = [];\n\n /**\n * @internal\n */\n this._signOnDemand = false;\n\n /**\n * This is the request's min backoff\n *\n * @internal\n * @type {number | null}\n */\n this._minBackoff = null;\n\n /**\n * This is the request's max backoff\n *\n * @internal\n * @type {number}\n */\n this._maxBackoff = 8000;\n\n /**\n * The operator that was used to execute this request.\n * The reason we save the operator in the request is because of the signing on\n * demand feature. This feature requires us to sign new request on each attempt\n * meaning if a client with an operator was used we'd need to sign with the operator\n * on each attempt.\n *\n * @internal\n * @type {ClientOperator | null}\n */\n this._operator = null;\n\n /**\n * The complete timeout for running the `execute()` method\n *\n * @internal\n * @type {number | null}\n */\n this._requestTimeout = null;\n\n /**\n * The grpc request timeout aka deadline.\n *\n * The reason we have this is because there were times that consensus nodes held the grpc\n * connection, but didn't return anything; not error nor regular response. This resulted\n * in some weird behavior in the SDKs. To fix this we've added a grpc deadline to prevent\n * nodes from stalling the executing of a request.\n *\n * @internal\n * @type {number | null}\n */\n this._grpcDeadline = null;\n\n /**\n * Logger\n *\n * @protected\n * @type {Logger | null}\n */\n this._logger = null;\n }\n\n /**\n * Get the list of node account IDs on the request. If no nodes are set, then null is returned.\n * The reasoning for this is simply \"legacy behavior\".\n *\n * @returns {?AccountId[]}\n */\n get nodeAccountIds() {\n if (this._nodeAccountIds.isEmpty) {\n return null;\n } else {\n this._nodeAccountIds.setLocked();\n return this._nodeAccountIds.list;\n }\n }\n\n /**\n * Set the node account IDs on the request\n *\n * @param {AccountId[]} nodeIds\n * @returns {this}\n */\n setNodeAccountIds(nodeIds) {\n // Set the node account IDs, and lock the list. This will require `execute`\n // to use these nodes instead of random nodes from the network.\n this._nodeAccountIds.setList(nodeIds).setLocked();\n return this;\n }\n\n /**\n * @deprecated\n * @returns {number}\n */\n get maxRetries() {\n console.warn(\"Deprecated: use maxAttempts instead\");\n return this.maxAttempts;\n }\n\n /**\n * @param {number} maxRetries\n * @returns {this}\n */\n setMaxRetries(maxRetries) {\n console.warn(\"Deprecated: use setMaxAttempts() instead\");\n return this.setMaxAttempts(maxRetries);\n }\n\n /**\n * Get the max attempts on the request\n *\n * @returns {number}\n */\n get maxAttempts() {\n return this._maxAttempts;\n }\n\n /**\n * Set the max attempts on the request\n *\n * @param {number} maxAttempts\n * @returns {this}\n */\n setMaxAttempts(maxAttempts) {\n this._maxAttempts = maxAttempts;\n\n return this;\n }\n\n /**\n * Get the grpc deadline\n *\n * @returns {?number}\n */\n get grpcDeadline() {\n return this._grpcDeadline;\n }\n\n /**\n * Set the grpc deadline\n *\n * @param {number} grpcDeadline\n * @returns {this}\n */\n setGrpcDeadline(grpcDeadline) {\n this._grpcDeadline = grpcDeadline;\n\n return this;\n }\n\n /**\n * Set the min backoff for the request\n *\n * @param {number} minBackoff\n * @returns {this}\n */\n setMinBackoff(minBackoff) {\n // Honestly we shouldn't be checking for null since that should be TypeScript's job.\n // Also verify that min backoff is not greater than max backoff.\n if (minBackoff == null) {\n throw new Error(\"minBackoff cannot be null.\");\n } else if (this._maxBackoff != null && minBackoff > this._maxBackoff) {\n throw new Error(\"minBackoff cannot be larger than maxBackoff.\");\n }\n this._minBackoff = minBackoff;\n return this;\n }\n\n /**\n * Get the min backoff\n *\n * @returns {number | null}\n */\n get minBackoff() {\n return this._minBackoff;\n }\n\n /**\n * Set the max backoff for the request\n *\n * @param {?number} maxBackoff\n * @returns {this}\n */\n setMaxBackoff(maxBackoff) {\n // Honestly we shouldn't be checking for null since that should be TypeScript's job.\n // Also verify that max backoff is not less than min backoff.\n if (maxBackoff == null) {\n throw new Error(\"maxBackoff cannot be null.\");\n } else if (this._minBackoff != null && maxBackoff < this._minBackoff) {\n throw new Error(\"maxBackoff cannot be smaller than minBackoff.\");\n }\n this._maxBackoff = maxBackoff;\n return this;\n }\n\n /**\n * Get the max backoff\n *\n * @returns {number}\n */\n get maxBackoff() {\n return this._maxBackoff;\n }\n\n /**\n * This method is responsible for doing any work before the executing process begins.\n * For paid queries this will result in executing a cost query, for transactions this\n * will make sure we save the operator and sign any requests that need to be signed\n * in case signing on demand is disabled.\n *\n * @abstract\n * @protected\n * @param {import(\"./client/Client.js\").default<Channel, *>} client\n * @returns {Promise<void>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _beforeExecute(client) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Create a protobuf request which will be passed into the `_execute()` method\n *\n * @abstract\n * @protected\n * @returns {Promise<RequestT>}\n */\n _makeRequestAsync() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * This name is a bit wrong now, but the purpose of this method is to map the\n * request and response into an error. This method will only be called when\n * `_shouldRetry` returned `ExecutionState.Error`\n *\n * @abstract\n * @internal\n * @param {RequestT} request\n * @param {ResponseT} response\n * @param {AccountId} nodeId\n * @returns {Error}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _mapStatusError(request, response, nodeId) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Map the request, response, and the node account ID used for this attempt into a response.\n * This method will only be called when `_shouldRetry` returned `ExecutionState.Finished`\n *\n * @abstract\n * @protected\n * @param {ResponseT} response\n * @param {AccountId} nodeAccountId\n * @param {RequestT} request\n * @returns {Promise<OutputT>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _mapResponse(response, nodeAccountId, request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Perform a single grpc call with the given request. Each request has it's own\n * required service so we just pass in channel, and it'$ the request's responsiblity\n * to use the right service and call the right grpc method.\n *\n * @abstract\n * @internal\n * @param {Channel} channel\n * @param {RequestT} request\n * @returns {Promise<ResponseT>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _execute(channel, request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Return the current transaction ID for the request. All requests which are\n * use the same transaction ID for each node, but the catch is that `Transaction`\n * implicitly supports chunked transactions. Meaning there could be multiple\n * transaction IDs stored in the request, and a different transaction ID will be used\n * on subsequent calls to `execute()`\n *\n * FIXME: This method can most likely be removed, although some further inspection\n * is required.\n *\n * @abstract\n * @protected\n * @returns {TransactionId}\n */\n _getTransactionId() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Return the log ID for this particular request\n *\n * Log IDs are simply a string constructed to make it easy to track each request's\n * execution even when mulitple requests are executing in parallel. Typically, this\n * method returns the format of `[<request type>.<timestamp of the transaction ID>]`\n *\n * Maybe we should deduplicate this using ${this.consturtor.name}\n *\n * @abstract\n * @internal\n * @returns {string}\n */\n _getLogId() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Serialize the request into bytes\n *\n * @abstract\n * @param {RequestT} request\n * @returns {Uint8Array}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _requestToBytes(request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Serialize the response into bytes\n *\n * @abstract\n * @param {ResponseT} response\n * @returns {Uint8Array}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _responseToBytes(response) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Determine if we should continue the execution process, error, or finish.\n *\n * FIXME: This method should really be called something else. Initially it returned\n * a boolean so `shouldRetry` made sense, but now it returns an enum, so the name\n * no longer makes sense.\n *\n * @abstract\n * @protected\n * @param {RequestT} request\n * @param {ResponseT} response\n * @returns {[Status, ExecutionState]}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _shouldRetry(request, response) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Determine if we should error based on the gRPC status\n *\n * Unlike `shouldRetry` this method does in fact still return a boolean\n *\n * @protected\n * @param {Error} error\n * @returns {boolean}\n */\n _shouldRetryExceptionally(error) {\n if (error instanceof GrpcServiceError) {\n return (\n error.status._code === GrpcStatus.Timeout._code ||\n error.status._code === GrpcStatus.Unavailable._code ||\n error.status._code === GrpcStatus.ResourceExhausted._code ||\n error.status._code === GrpcStatus.GrpcWeb._code ||\n (error.status._code === GrpcStatus.Internal._code &&\n RST_STREAM.test(error.message))\n );\n } else {\n // if we get to the 'else' statement, the 'error' is instanceof 'HttpError'\n // and in this case, we have to retry always\n return true;\n }\n }\n\n /**\n * A helper method for setting the operator on the request\n *\n * @internal\n * @param {AccountId} accountId\n * @param {PublicKey} publicKey\n * @param {(message: Uint8Array) => Promise<Uint8Array>} transactionSigner\n * @returns {this}\n */\n _setOperatorWith(accountId, publicKey, transactionSigner) {\n this._operator = {\n transactionSigner,\n accountId,\n publicKey,\n };\n return this;\n }\n\n /**\n * Execute this request using the signer\n *\n * This method is part of the signature providers feature\n * https://hips.hedera.com/hip/hip-338\n *\n * @param {Signer} signer\n * @returns {Promise<OutputT>}\n */\n async executeWithSigner(signer) {\n return signer.call(this);\n }\n\n /**\n * @returns {boolean}\n * @abstract\n * @protected\n */\n isBatchedAndNotBatchTransaction() {\n return false;\n }\n\n /**\n * Execute the request using a client and an optional request timeout\n *\n * @template {Channel} ChannelT\n * @template {MirrorChannel} MirrorChannelT\n * @param {import(\"./client/Client.js\").default<ChannelT, MirrorChannelT>} client\n * @param {number=} requestTimeout\n * @returns {Promise<OutputT>}\n */\n async execute(client, requestTimeout) {\n // we check if its local node then backoff mechanism should be disabled\n // and we increase the retry attempts\n const isLocalNode = client.network[\"127.0.0.1:50211\"] != null;\n\n if (this.isBatchedAndNotBatchTransaction()) {\n throw new Error(\n \"Cannot execute batchified transaction outside of BatchTransaction\",\n );\n }\n\n // If the logger on the request is not set, use the logger in client\n // (if set, otherwise do not use logger)\n this._logger =\n this._logger == null\n ? client._logger != null\n ? client._logger\n : null\n : this._logger;\n\n // If the request timeout is set on the request we'll prioritize that instead\n // of the parameter provided, and if the parameter isn't provided we'll\n // use the default request timeout on client\n if (this._requestTimeout == null) {\n this._requestTimeout =\n requestTimeout != null ? requestTimeout : client.requestTimeout;\n }\n\n // Some request need to perform additional requests before the executing\n // such as paid queries need to fetch the cost of the query before\n // finally executing the actual query.\n await this._beforeExecute(client);\n\n // If the max backoff on the request is not set, use the default value in client\n if (this._maxBackoff == null) {\n this._maxBackoff = client.maxBackoff;\n }\n\n // If the min backoff on the request is not set, use the default value in client\n if (this._minBackoff == null) {\n this._minBackoff = client.minBackoff;\n }\n\n // Save the start time to be used later with request timeout\n const startTime = Date.now();\n\n // Saves each error we get so when we err due to max attempts exceeded we'll have\n // the last error that was returned by the consensus node\n let persistentError = null;\n\n // If the max attempts on the request is not set, use the default value in client\n // If the default value in client is not set, use a default of 10.\n //\n // FIXME: current implementation is wrong, update to follow comment above.\n // ... existing code ...\n const LOCAL_NODE_ATTEMPTS = 1000;\n const maxAttempts = isLocalNode\n ? LOCAL_NODE_ATTEMPTS\n : client._maxAttempts ?? this._maxAttempts;\n\n // Checks if has a valid nodes to which the TX can be sent\n if (this.transactionNodeIds.length) {\n const nodeAccountIds = this._nodeAccountIds.list.map((nodeId) =>\n nodeId.toString(),\n );\n\n const hasValidNodes = this.transactionNodeIds.some((nodeId) =>\n nodeAccountIds.includes(nodeId),\n );\n\n if (!hasValidNodes) {\n const displayNodeAccountIds =\n nodeAccountIds.length > 2\n ? `${nodeAccountIds.slice(0, 2).join(\", \")} ...`\n : nodeAccountIds.join(\", \");\n const isSingleNode = nodeAccountIds.length === 1;\n\n throw new Error(\n `Attempting to execute a transaction against node${\n isSingleNode ? \"\" : \"s\"\n } ${displayNodeAccountIds}, ` +\n `which ${\n isSingleNode ? \"is\" : \"are\"\n } not included in the Client's node list. Please review your Client configuration.`,\n );\n }\n }\n\n // The retry loop\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n // Determine if we've exceeded request timeout\n if (\n this._requestTimeout != null &&\n startTime + this._requestTimeout <= Date.now()\n ) {\n throw new MaxAttemptsOrTimeoutError(\n `timeout exceeded`,\n this._nodeAccountIds.isEmpty\n ? \"No node account ID set\"\n : this._nodeAccountIds.current.toString(),\n );\n }\n\n let nodeAccountId;\n let node;\n\n if (this._nodeAccountIds.isEmpty) {\n node = client._network.getNode();\n nodeAccountId = node.accountId;\n this._nodeAccountIds.setList([nodeAccountId]);\n } else {\n nodeAccountId = this._nodeAccountIds.current;\n node = client._network.getNode(nodeAccountId);\n }\n\n if (node == null) {\n throw new Error(\n `NodeAccountId not recognized: ${nodeAccountId.toString()}`,\n );\n }\n\n if (this.transactionNodeIds.length) {\n const isNodeAccountIdValid = this.transactionNodeIds.includes(\n nodeAccountId.toString(),\n );\n\n if (!isNodeAccountIdValid) {\n console.error(\n `Attempting to execute a transaction against node ${nodeAccountId.toString()}, which is not included in the Client's node list. Please review your Client configuration.`,\n );\n\n this._nodeAccountIds.advance();\n continue;\n }\n }\n\n // Get the log ID for the request.\n const logId = this._getLogId();\n if (this._logger) {\n this._logger.debug(\n `[${logId}] Node AccountID: ${node.accountId.toString()}, IP: ${node.address.toString()}`,\n );\n }\n\n const channel = node.getChannel();\n const request = await this._makeRequestAsync();\n\n let response;\n\n if (!node.isHealthy()) {\n const isLastNode =\n this._nodeAccountIds.index ===\n this._nodeAccountIds.list.length - 1;\n\n // Check if the request is a transaction receipt or record\n // request to retry 10 times, because getReceiptQuery/getRecordQuery\n // are single node requests\n if (\n isTransactionReceiptOrRecordRequest(request) ||\n isLocalNode\n ) {\n await delayForAttempt(\n isLocalNode,\n attempt,\n this._minBackoff,\n this._maxBackoff,\n );\n continue;\n }\n\n if (isLastNode || this._nodeAccountIds.length <= 1) {\n throw new Error(\n `Network connectivity issue: All nodes are unhealthy. Original node list: ${this._nodeAccountIds.list.join(\n \", \",\n )}`,\n );\n }\n\n if (this._logger) {\n this._logger.debug(\n `[${logId}] Node is not healthy, trying the next node.`,\n );\n }\n\n this._nodeAccountIds.advance();\n continue;\n }\n\n this._nodeAccountIds.advance();\n\n try {\n // Race the execution promise against the grpc timeout to prevent grpc connections\n // from blocking this request\n const promises = [];\n\n // If a grpc deadline is est, we should race it, otherwise the only thing in the\n // list of promises will be the execution promise.\n if (this._grpcDeadline != null) {\n promises.push(\n // eslint-disable-next-line ie11/no-loop-func\n new Promise((_, reject) =>\n setTimeout(\n // eslint-disable-next-line ie11/no-loop-func\n () =>\n reject(new Error(\"grpc deadline exceeded\")),\n /** @type {number=} */ (this._grpcDeadline),\n ),\n ),\n );\n }\n if (this._logger) {\n this._logger.trace(\n `[${this._getLogId()}] sending protobuf ${hex.encode(\n this._requestToBytes(request),\n )}`,\n );\n }\n\n promises.push(this._execute(channel, request));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n response = /** @type {ResponseT} */ (\n await Promise.race(promises)\n );\n } catch (err) {\n // If we received a grpc status error we need to determine if\n // we should retry on this error, or err from the request entirely.\n const error = GrpcServiceError._fromResponse(\n /** @type {Error} */ (err),\n );\n\n // Save the error in case we retry\n persistentError = error;\n if (this._logger) {\n this._logger.debug(\n `[${logId}] received error ${JSON.stringify(error)}`,\n );\n }\n\n if (\n (error instanceof GrpcServiceError ||\n error instanceof HttpError) &&\n this._shouldRetryExceptionally(error) &&\n attempt <= maxAttempts\n ) {\n // Increase the backoff for the particular node and remove it from\n // the healthy node list\n if (this._logger) {\n this._logger.debug(\n `[${this._getLogId()}] node with accountId: ${node.accountId.toString()} and proxy IP: ${node.address.toString()} is unhealthy`,\n );\n }\n\n client._network.increaseBackoff(node);\n continue;\n }\n\n throw err;\n }\n if (this._logger) {\n this._logger.trace(\n `[${this._getLogId()}] sending protobuf ${hex.encode(\n this._responseToBytes(response),\n )}`,\n );\n }\n\n // If we didn't receive an error we should decrease the current nodes backoff\n // in case it is a recovering node\n client._network.decreaseBackoff(node);\n\n // Determine what execution state we're in by the response\n // For transactions this would be as simple as checking the response status is `OK`\n // while for _most_ queries it would check if the response status is `SUCCESS`\n // The only odd balls are `TransactionReceiptQuery` and `TransactionRecordQuery`\n const [status, shouldRetry] = this._shouldRetry(request, response);\n if (\n status.toString() !== Status.Ok.toString() &&\n status.toString() !== Status.Success.toString()\n ) {\n persistentError = status;\n }\n\n // Determine by the executing state what we should do\n switch (shouldRetry) {\n case ExecutionState.Retry:\n await delayForAttempt(\n isLocalNode,\n attempt,\n this._minBackoff,\n this._maxBackoff,\n );\n continue;\n case ExecutionState.Finished:\n return this._mapResponse(response, nodeAccountId, request);\n case ExecutionState.Error:\n throw this._mapStatusError(\n request,\n response,\n nodeAccountId,\n );\n default:\n throw new Error(\n \"(BUG) non-exhaustive switch statement for `ExecutionState`\",\n );\n }\n }\n\n // We'll only get here if we've run out of attempts, so we return an error wrapping the\n // persistent error we saved before.\n\n throw new MaxAttemptsOrTimeoutError(\n `max attempts of ${maxAttempts.toString()} was reached for request with last error being: ${\n persistentError != null ? persistentError.toString() : \"\"\n }`,\n this._nodeAccountIds.current.toString(),\n );\n }\n\n /**\n * The current purpose of this method is to easily support signature providers since\n * signature providers need to serialize _any_ request into bytes. `Query` and `Transaction`\n * already implement `toBytes()` so it only made sense to make it available here too.\n *\n * @abstract\n * @returns {Uint8Array}\n */\n toBytes() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Set logger\n *\n * @param {Logger} logger\n * @returns {this}\n */\n setLogger(logger) {\n this._logger = logger;\n return this;\n }\n\n /**\n * Get logger if set\n *\n * @returns {?Logger}\n */\n get logger() {\n return this._logger;\n }\n}\n\n/**\n * Checks if the request is a transaction receipt or record request\n *\n * @template T\n * @param {T} request - The request to check\n * @returns {boolean} - True if the request is a transaction receipt or record\n */\nfunction isTransactionReceiptOrRecordRequest(request) {\n if (typeof request !== \"object\" || request === null) {\n return false;\n }\n\n return (\n \"transactionGetReceipt\" in request || \"transactionGetRecord\" in request\n );\n}\n\n/**\n * A simple function that returns a promise timeout for a specific period of time\n *\n * @param {boolean} isLocalNode\n * @param {number} attempt\n * @param {number} minBackoff\n * @param {number} maxBackoff\n * @returns {Promise<void>}\n */\nfunction delayForAttempt(isLocalNode, attempt, minBackoff, maxBackoff) {\n if (isLocalNode) {\n return new Promise((resolve) => setTimeout(resolve, minBackoff));\n }\n\n // 0.1s, 0.2s, 0.4s, 0.8s, ...\n const ms = Math.min(\n Math.floor(minBackoff * Math.pow(2, attempt)),\n maxBackoff,\n );\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"names":["ExecutionState","Finished","Retry","Error","RST_STREAM","DEFAULT_MAX_ATTEMPTS","Executable","constructor","this","_maxAttempts","_nodeAccountIds","List","transactionNodeIds","_signOnDemand","_minBackoff","_maxBackoff","_operator","_requestTimeout","_grpcDeadline","_logger","nodeAccountIds","isEmpty","setLocked","list","setNodeAccountIds","nodeIds","setList","maxRetries","console","warn","maxAttempts","setMaxRetries","setMaxAttempts","grpcDeadline","setGrpcDeadline","setMinBackoff","minBackoff","setMaxBackoff","maxBackoff","_beforeExecute","client","_makeRequestAsync","_mapStatusError","request","response","nodeId","_mapResponse","nodeAccountId","_execute","channel","_getTransactionId","_getLogId","_requestToBytes","_responseToBytes","_shouldRetry","_shouldRetryExceptionally","error","GrpcServiceError","status","_code","GrpcStatus","Timeout","Unavailable","ResourceExhausted","GrpcWeb","Internal","test","message","_setOperatorWith","accountId","publicKey","transactionSigner","executeWithSigner","signer","call","isBatchedAndNotBatchTransaction","execute","requestTimeout","isLocalNode","network","startTime","Date","now","persistentError","length","map","toString","some","includes","displayNodeAccountIds","slice","join","isSingleNode","attempt","MaxAttemptsOrTimeoutError","current","node","_network","getNode","advance","logId","debug","address","getChannel","isHealthy","isLastNode","index","isTransactionReceiptOrRecordRequest","delayForAttempt","promises","push","Promise","_","reject","setTimeout","trace","hex.encode","race","err","_fromResponse","JSON","stringify","HttpError","increaseBackoff","decreaseBackoff","shouldRetry","Status","Ok","Success","toBytes","setLogger","logger","resolve","ms","Math","min","floor","pow"],"mappings":"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"}
1
+ {"version":3,"file":"Executable.js","sources":["../src/Executable.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport GrpcServiceError from \"./grpc/GrpcServiceError.js\";\nimport GrpcStatus from \"./grpc/GrpcStatus.js\";\nimport List from \"./transaction/List.js\";\nimport * as hex from \"./encoding/hex.js\";\nimport HttpError from \"./http/HttpError.js\";\nimport Status from \"./Status.js\";\nimport MaxAttemptsOrTimeoutError from \"./MaxAttemptsOrTimeoutError.js\";\n\n/**\n * @typedef {import(\"./account/AccountId.js\").default} AccountId\n * @typedef {import(\"./channel/Channel.js\").default} Channel\n * @typedef {import(\"./channel/MirrorChannel.js\").default} MirrorChannel\n * @typedef {import(\"./transaction/TransactionId.js\").default} TransactionId\n * @typedef {import(\"./client/Client.js\").ClientOperator} ClientOperator\n * @typedef {import(\"./Signer.js\").Signer} Signer\n * @typedef {import(\"./PublicKey.js\").default} PublicKey\n * @typedef {import(\"./logger/Logger.js\").default} Logger\n */\n\n/**\n * @enum {string}\n */\nexport const ExecutionState = {\n Finished: \"Finished\",\n Retry: \"Retry\",\n Error: \"Error\",\n};\n\nexport const RST_STREAM = /\\brst[^0-9a-zA-Z]stream\\b/i;\nexport const DEFAULT_MAX_ATTEMPTS = 10;\n\n/**\n * @abstract\n * @internal\n * @template RequestT\n * @template ResponseT\n * @template OutputT\n */\nexport default class Executable {\n constructor() {\n /**\n * The number of times we can retry the grpc call\n *\n * @internal\n * @type {number}\n */\n this._maxAttempts = DEFAULT_MAX_ATTEMPTS;\n\n /**\n * List of node account IDs for each transaction that has been\n * built.\n *\n * @internal\n * @type {List<AccountId>}\n */\n this._nodeAccountIds = new List();\n\n /**\n * List of the transaction node account IDs to check if\n * the node account ID of the request is in the list\n *\n * @protected\n * @type {Array<string>}\n */\n this.transactionNodeIds = [];\n\n /**\n * @internal\n */\n this._signOnDemand = false;\n\n /**\n * This is the request's min backoff\n *\n * @internal\n * @type {number | null}\n */\n this._minBackoff = null;\n\n /**\n * This is the request's max backoff\n *\n * @internal\n * @type {number}\n */\n this._maxBackoff = 8000;\n\n /**\n * The operator that was used to execute this request.\n * The reason we save the operator in the request is because of the signing on\n * demand feature. This feature requires us to sign new request on each attempt\n * meaning if a client with an operator was used we'd need to sign with the operator\n * on each attempt.\n *\n * @internal\n * @type {ClientOperator | null}\n */\n this._operator = null;\n\n /**\n * The complete timeout for running the `execute()` method\n *\n * @internal\n * @type {number | null}\n */\n this._requestTimeout = null;\n\n /**\n * The grpc request timeout aka deadline.\n *\n * The reason we have this is because there were times that consensus nodes held the grpc\n * connection, but didn't return anything; not error nor regular response. This resulted\n * in some weird behavior in the SDKs. To fix this we've added a grpc deadline to prevent\n * nodes from stalling the executing of a request.\n *\n * @internal\n * @type {number | null}\n */\n this._grpcDeadline = null;\n\n /**\n * Logger\n *\n * @protected\n * @type {Logger | null}\n */\n this._logger = null;\n }\n\n /**\n * Get the list of node account IDs on the request. If no nodes are set, then null is returned.\n * The reasoning for this is simply \"legacy behavior\".\n *\n * @returns {?AccountId[]}\n */\n get nodeAccountIds() {\n if (this._nodeAccountIds.isEmpty) {\n return null;\n } else {\n this._nodeAccountIds.setLocked();\n return this._nodeAccountIds.list;\n }\n }\n\n /**\n * Set the node account IDs on the request\n *\n * @param {AccountId[]} nodeIds\n * @returns {this}\n */\n setNodeAccountIds(nodeIds) {\n // Set the node account IDs, and lock the list. This will require `execute`\n // to use these nodes instead of random nodes from the network.\n this._nodeAccountIds.setList(nodeIds).setLocked();\n return this;\n }\n\n /**\n * @deprecated\n * @returns {number}\n */\n get maxRetries() {\n console.warn(\"Deprecated: use maxAttempts instead\");\n return this.maxAttempts;\n }\n\n /**\n * @param {number} maxRetries\n * @returns {this}\n */\n setMaxRetries(maxRetries) {\n console.warn(\"Deprecated: use setMaxAttempts() instead\");\n return this.setMaxAttempts(maxRetries);\n }\n\n /**\n * Get the max attempts on the request\n *\n * @returns {number}\n */\n get maxAttempts() {\n return this._maxAttempts;\n }\n\n /**\n * Set the max attempts on the request\n *\n * @param {number} maxAttempts\n * @returns {this}\n */\n setMaxAttempts(maxAttempts) {\n this._maxAttempts = maxAttempts;\n\n return this;\n }\n\n /**\n * Get the grpc deadline\n *\n * @returns {?number}\n */\n get grpcDeadline() {\n return this._grpcDeadline;\n }\n\n /**\n * Set the grpc deadline\n *\n * @param {number} grpcDeadline\n * @returns {this}\n */\n setGrpcDeadline(grpcDeadline) {\n this._grpcDeadline = grpcDeadline;\n\n return this;\n }\n\n /**\n * Set the min backoff for the request\n *\n * @param {number} minBackoff\n * @returns {this}\n */\n setMinBackoff(minBackoff) {\n // Honestly we shouldn't be checking for null since that should be TypeScript's job.\n // Also verify that min backoff is not greater than max backoff.\n if (minBackoff == null) {\n throw new Error(\"minBackoff cannot be null.\");\n } else if (this._maxBackoff != null && minBackoff > this._maxBackoff) {\n throw new Error(\"minBackoff cannot be larger than maxBackoff.\");\n }\n this._minBackoff = minBackoff;\n return this;\n }\n\n /**\n * Get the min backoff\n *\n * @returns {number | null}\n */\n get minBackoff() {\n return this._minBackoff;\n }\n\n /**\n * Set the max backoff for the request\n *\n * @param {?number} maxBackoff\n * @returns {this}\n */\n setMaxBackoff(maxBackoff) {\n // Honestly we shouldn't be checking for null since that should be TypeScript's job.\n // Also verify that max backoff is not less than min backoff.\n if (maxBackoff == null) {\n throw new Error(\"maxBackoff cannot be null.\");\n } else if (this._minBackoff != null && maxBackoff < this._minBackoff) {\n throw new Error(\"maxBackoff cannot be smaller than minBackoff.\");\n }\n this._maxBackoff = maxBackoff;\n return this;\n }\n\n /**\n * Get the max backoff\n *\n * @returns {number}\n */\n get maxBackoff() {\n return this._maxBackoff;\n }\n\n /**\n * This method is responsible for doing any work before the executing process begins.\n * For paid queries this will result in executing a cost query, for transactions this\n * will make sure we save the operator and sign any requests that need to be signed\n * in case signing on demand is disabled.\n *\n * @abstract\n * @protected\n * @param {import(\"./client/Client.js\").default<Channel, *>} client\n * @returns {Promise<void>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _beforeExecute(client) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Create a protobuf request which will be passed into the `_execute()` method\n *\n * @abstract\n * @protected\n * @returns {Promise<RequestT>}\n */\n _makeRequestAsync() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * This name is a bit wrong now, but the purpose of this method is to map the\n * request and response into an error. This method will only be called when\n * `_shouldRetry` returned `ExecutionState.Error`\n *\n * @abstract\n * @internal\n * @param {RequestT} request\n * @param {ResponseT} response\n * @param {AccountId} nodeId\n * @returns {Error}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _mapStatusError(request, response, nodeId) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Map the request, response, and the node account ID used for this attempt into a response.\n * This method will only be called when `_shouldRetry` returned `ExecutionState.Finished`\n *\n * @abstract\n * @protected\n * @param {ResponseT} response\n * @param {AccountId} nodeAccountId\n * @param {RequestT} request\n * @returns {Promise<OutputT>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _mapResponse(response, nodeAccountId, request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Perform a single grpc call with the given request. Each request has it's own\n * required service so we just pass in channel, and it'$ the request's responsiblity\n * to use the right service and call the right grpc method.\n *\n * @abstract\n * @internal\n * @param {Channel} channel\n * @param {RequestT} request\n * @returns {Promise<ResponseT>}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _execute(channel, request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Return the current transaction ID for the request. All requests which are\n * use the same transaction ID for each node, but the catch is that `Transaction`\n * implicitly supports chunked transactions. Meaning there could be multiple\n * transaction IDs stored in the request, and a different transaction ID will be used\n * on subsequent calls to `execute()`\n *\n * FIXME: This method can most likely be removed, although some further inspection\n * is required.\n *\n * @abstract\n * @protected\n * @returns {TransactionId}\n */\n _getTransactionId() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Return the log ID for this particular request\n *\n * Log IDs are simply a string constructed to make it easy to track each request's\n * execution even when mulitple requests are executing in parallel. Typically, this\n * method returns the format of `[<request type>.<timestamp of the transaction ID>]`\n *\n * Maybe we should deduplicate this using ${this.consturtor.name}\n *\n * @abstract\n * @internal\n * @returns {string}\n */\n _getLogId() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Serialize the request into bytes\n *\n * @abstract\n * @param {RequestT} request\n * @returns {Uint8Array}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _requestToBytes(request) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Serialize the response into bytes\n *\n * @abstract\n * @param {ResponseT} response\n * @returns {Uint8Array}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _responseToBytes(response) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Determine if we should continue the execution process, error, or finish.\n *\n * FIXME: This method should really be called something else. Initially it returned\n * a boolean so `shouldRetry` made sense, but now it returns an enum, so the name\n * no longer makes sense.\n *\n * @abstract\n * @protected\n * @param {RequestT} request\n * @param {ResponseT} response\n * @returns {[Status, ExecutionState]}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _shouldRetry(request, response) {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Determine if we should error based on the gRPC status\n *\n * Unlike `shouldRetry` this method does in fact still return a boolean\n *\n * @protected\n * @param {Error} error\n * @returns {boolean}\n */\n _shouldRetryExceptionally(error) {\n if (error instanceof GrpcServiceError) {\n return (\n error.status._code === GrpcStatus.Timeout._code ||\n error.status._code === GrpcStatus.DeadlineExceeded._code ||\n error.status._code === GrpcStatus.Unavailable._code ||\n error.status._code === GrpcStatus.ResourceExhausted._code ||\n error.status._code === GrpcStatus.GrpcWeb._code ||\n (error.status._code === GrpcStatus.Internal._code &&\n RST_STREAM.test(error.message))\n );\n } else {\n // if we get to the 'else' statement, the 'error' is instanceof 'HttpError'\n // and in this case, we have to retry always\n return true;\n }\n }\n\n /**\n * A helper method for setting the operator on the request\n *\n * @internal\n * @param {AccountId} accountId\n * @param {PublicKey} publicKey\n * @param {(message: Uint8Array) => Promise<Uint8Array>} transactionSigner\n * @returns {this}\n */\n _setOperatorWith(accountId, publicKey, transactionSigner) {\n this._operator = {\n transactionSigner,\n accountId,\n publicKey,\n };\n return this;\n }\n\n /**\n * Execute this request using the signer\n *\n * This method is part of the signature providers feature\n * https://hips.hedera.com/hip/hip-338\n *\n * @param {Signer} signer\n * @returns {Promise<OutputT>}\n */\n async executeWithSigner(signer) {\n return signer.call(this);\n }\n\n /**\n * @returns {boolean}\n * @abstract\n * @protected\n */\n isBatchedAndNotBatchTransaction() {\n return false;\n }\n\n /**\n * Execute the request using a client and an optional request timeout\n *\n * @template {Channel} ChannelT\n * @template {MirrorChannel} MirrorChannelT\n * @param {import(\"./client/Client.js\").default<ChannelT, MirrorChannelT>} client\n * @param {number=} requestTimeout\n * @returns {Promise<OutputT>}\n */\n async execute(client, requestTimeout) {\n // we check if its local node then backoff mechanism should be disabled\n // and we increase the retry attempts\n const isLocalNode = client.network[\"127.0.0.1:50211\"] != null;\n\n if (this.isBatchedAndNotBatchTransaction()) {\n throw new Error(\n \"Cannot execute batchified transaction outside of BatchTransaction\",\n );\n }\n\n // If the logger on the request is not set, use the logger in client\n // (if set, otherwise do not use logger)\n this._logger =\n this._logger == null\n ? client._logger != null\n ? client._logger\n : null\n : this._logger;\n\n // If the request timeout is set on the request we'll prioritize that instead\n // of the parameter provided, and if the parameter isn't provided we'll\n // use the default request timeout on client\n if (this._requestTimeout == null) {\n this._requestTimeout =\n requestTimeout != null ? requestTimeout : client.requestTimeout;\n }\n\n // If the grpc deadline is not set on the request, use the default value from client\n if (this._grpcDeadline == null) {\n this._grpcDeadline = client.grpcDeadline;\n }\n\n // Some request need to perform additional requests before the executing\n // such as paid queries need to fetch the cost of the query before\n // finally executing the actual query.\n await this._beforeExecute(client);\n\n // If the max backoff on the request is not set, use the default value in client\n if (this._maxBackoff == null) {\n this._maxBackoff = client.maxBackoff;\n }\n\n // If the min backoff on the request is not set, use the default value in client\n if (this._minBackoff == null) {\n this._minBackoff = client.minBackoff;\n }\n\n // Save the start time to be used later with request timeout\n const startTime = Date.now();\n\n // Saves each error we get so when we err due to max attempts exceeded we'll have\n // the last error that was returned by the consensus node\n let persistentError = null;\n\n // If the max attempts on the request is not set, use the default value in client\n // If the default value in client is not set, use a default of 10.\n //\n // FIXME: current implementation is wrong, update to follow comment above.\n // ... existing code ...\n const LOCAL_NODE_ATTEMPTS = 1000;\n const maxAttempts = isLocalNode\n ? LOCAL_NODE_ATTEMPTS\n : client._maxAttempts ?? this._maxAttempts;\n\n // Checks if has a valid nodes to which the TX can be sent\n if (this.transactionNodeIds.length) {\n const nodeAccountIds = this._nodeAccountIds.list.map((nodeId) =>\n nodeId.toString(),\n );\n\n const hasValidNodes = this.transactionNodeIds.some((nodeId) =>\n nodeAccountIds.includes(nodeId),\n );\n\n if (!hasValidNodes) {\n const displayNodeAccountIds =\n nodeAccountIds.length > 2\n ? `${nodeAccountIds.slice(0, 2).join(\", \")} ...`\n : nodeAccountIds.join(\", \");\n const isSingleNode = nodeAccountIds.length === 1;\n\n throw new Error(\n `Attempting to execute a transaction against node${\n isSingleNode ? \"\" : \"s\"\n } ${displayNodeAccountIds}, ` +\n `which ${\n isSingleNode ? \"is\" : \"are\"\n } not included in the Client's node list. Please review your Client configuration.`,\n );\n }\n }\n\n // The retry loop\n for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {\n // Determine if we've exceeded request timeout\n if (\n this._requestTimeout != null &&\n startTime + this._requestTimeout <= Date.now()\n ) {\n throw new MaxAttemptsOrTimeoutError(\n `timeout exceeded`,\n this._nodeAccountIds.isEmpty\n ? \"No node account ID set\"\n : this._nodeAccountIds.current.toString(),\n );\n }\n\n let nodeAccountId;\n let node;\n\n if (this._nodeAccountIds.isEmpty) {\n node = client._network.getNode();\n nodeAccountId = node.accountId;\n this._nodeAccountIds.setList([nodeAccountId]);\n } else {\n nodeAccountId = this._nodeAccountIds.current;\n node = client._network.getNode(nodeAccountId);\n }\n\n if (node == null) {\n throw new Error(\n `NodeAccountId not recognized: ${nodeAccountId.toString()}`,\n );\n }\n\n if (this.transactionNodeIds.length) {\n const isNodeAccountIdValid = this.transactionNodeIds.includes(\n nodeAccountId.toString(),\n );\n\n if (!isNodeAccountIdValid) {\n console.error(\n `Attempting to execute a transaction against node ${nodeAccountId.toString()}, which is not included in the Client's node list. Please review your Client configuration.`,\n );\n\n this._nodeAccountIds.advance();\n continue;\n }\n }\n\n // Get the log ID for the request.\n const logId = this._getLogId();\n if (this._logger) {\n this._logger.debug(\n `[${logId}] Node AccountID: ${node.accountId.toString()}, IP: ${node.address.toString()}`,\n );\n }\n\n const channel = node.getChannel();\n\n // Set the gRPC deadline on the channel if this query has a custom deadline\n if (this._grpcDeadline != null) {\n channel.setGrpcDeadline(this._grpcDeadline);\n }\n\n const request = await this._makeRequestAsync();\n\n let response;\n\n if (!node.isHealthy()) {\n const isLastNode =\n this._nodeAccountIds.index ===\n this._nodeAccountIds.list.length - 1;\n\n // Check if the request is a transaction receipt or record\n // request to retry 10 times, because getReceiptQuery/getRecordQuery\n // are single node requests\n if (\n isTransactionReceiptOrRecordRequest(request) ||\n isLocalNode\n ) {\n await delayForAttempt(\n isLocalNode,\n attempt,\n this._minBackoff,\n this._maxBackoff,\n );\n continue;\n }\n\n if (isLastNode || this._nodeAccountIds.length <= 1) {\n throw new Error(\n `Network connectivity issue: All nodes are unhealthy. Original node list: ${this._nodeAccountIds.list.join(\n \", \",\n )}`,\n );\n }\n\n if (this._logger) {\n this._logger.debug(\n `[${logId}] Node is not healthy, trying the next node.`,\n );\n }\n\n this._nodeAccountIds.advance();\n continue;\n }\n\n this._nodeAccountIds.advance();\n\n try {\n // Race the execution promise against the grpc timeout to prevent grpc connections\n // from blocking this request\n const promises = [];\n\n // If a grpc deadline is set, we should race it, otherwise the only thing in the\n // list of promises will be the execution promise.\n if (this._grpcDeadline != null) {\n promises.push(\n // eslint-disable-next-line ie11/no-loop-func\n new Promise((_, reject) =>\n setTimeout(\n // eslint-disable-next-line ie11/no-loop-func\n () =>\n reject(\n new GrpcServiceError(\n GrpcStatus.DeadlineExceeded,\n ),\n ),\n /** @type {number=} */ (this._grpcDeadline),\n ),\n ),\n );\n }\n if (this._logger) {\n this._logger.trace(\n `[${this._getLogId()}] sending protobuf ${hex.encode(\n this._requestToBytes(request),\n )}`,\n );\n }\n\n promises.push(this._execute(channel, request));\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n response = /** @type {ResponseT} */ (\n await Promise.race(promises)\n );\n } catch (err) {\n // If we received a grpc status error we need to determine if\n // we should retry on this error, or err from the request entirely.\n const error = GrpcServiceError._fromResponse(\n /** @type {Error} */ (err),\n );\n\n // Save the error in case we retry\n persistentError = error;\n if (this._logger) {\n this._logger.debug(\n `[${logId}] received error ${JSON.stringify(error)}`,\n );\n }\n\n if (\n (error instanceof GrpcServiceError ||\n error instanceof HttpError) &&\n this._shouldRetryExceptionally(error) &&\n attempt <= maxAttempts\n ) {\n // Increase the backoff for the particular node and remove it from\n // the healthy node list\n if (this._logger) {\n this._logger.debug(\n `[${this._getLogId()}] node with accountId: ${node.accountId.toString()} and proxy IP: ${node.address.toString()} is unhealthy`,\n );\n }\n\n client._network.increaseBackoff(node);\n continue;\n }\n\n throw err;\n }\n if (this._logger) {\n this._logger.trace(\n `[${this._getLogId()}] sending protobuf ${hex.encode(\n this._responseToBytes(response),\n )}`,\n );\n }\n\n // If we didn't receive an error we should decrease the current nodes backoff\n // in case it is a recovering node\n client._network.decreaseBackoff(node);\n\n // Determine what execution state we're in by the response\n // For transactions this would be as simple as checking the response status is `OK`\n // while for _most_ queries it would check if the response status is `SUCCESS`\n // The only odd balls are `TransactionReceiptQuery` and `TransactionRecordQuery`\n const [status, shouldRetry] = this._shouldRetry(request, response);\n if (\n status.toString() !== Status.Ok.toString() &&\n status.toString() !== Status.Success.toString()\n ) {\n persistentError = status;\n }\n\n // Determine by the executing state what we should do\n switch (shouldRetry) {\n case ExecutionState.Retry:\n await delayForAttempt(\n isLocalNode,\n attempt,\n this._minBackoff,\n this._maxBackoff,\n );\n continue;\n case ExecutionState.Finished:\n return this._mapResponse(response, nodeAccountId, request);\n case ExecutionState.Error:\n throw this._mapStatusError(\n request,\n response,\n nodeAccountId,\n );\n default:\n throw new Error(\n \"(BUG) non-exhaustive switch statement for `ExecutionState`\",\n );\n }\n }\n\n // We'll only get here if we've run out of attempts, so we return an error wrapping the\n // persistent error we saved before.\n\n throw new MaxAttemptsOrTimeoutError(\n `max attempts of ${maxAttempts.toString()} was reached for request with last error being: ${\n persistentError != null ? persistentError.toString() : \"\"\n }`,\n this._nodeAccountIds.current.toString(),\n );\n }\n\n /**\n * The current purpose of this method is to easily support signature providers since\n * signature providers need to serialize _any_ request into bytes. `Query` and `Transaction`\n * already implement `toBytes()` so it only made sense to make it available here too.\n *\n * @abstract\n * @returns {Uint8Array}\n */\n toBytes() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * Set logger\n *\n * @param {Logger} logger\n * @returns {this}\n */\n setLogger(logger) {\n this._logger = logger;\n return this;\n }\n\n /**\n * Get logger if set\n *\n * @returns {?Logger}\n */\n get logger() {\n return this._logger;\n }\n}\n\n/**\n * Checks if the request is a transaction receipt or record request\n *\n * @template T\n * @param {T} request - The request to check\n * @returns {boolean} - True if the request is a transaction receipt or record\n */\nfunction isTransactionReceiptOrRecordRequest(request) {\n if (typeof request !== \"object\" || request === null) {\n return false;\n }\n\n return (\n \"transactionGetReceipt\" in request || \"transactionGetRecord\" in request\n );\n}\n\n/**\n * A simple function that returns a promise timeout for a specific period of time\n *\n * @param {boolean} isLocalNode\n * @param {number} attempt\n * @param {number} minBackoff\n * @param {number} maxBackoff\n * @returns {Promise<void>}\n */\nfunction delayForAttempt(isLocalNode, attempt, minBackoff, maxBackoff) {\n if (isLocalNode) {\n return new Promise((resolve) => setTimeout(resolve, minBackoff));\n }\n\n // 0.1s, 0.2s, 0.4s, 0.8s, ...\n const ms = Math.min(\n Math.floor(minBackoff * Math.pow(2, attempt)),\n maxBackoff,\n );\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"names":["ExecutionState","Finished","Retry","Error","RST_STREAM","DEFAULT_MAX_ATTEMPTS","Executable","constructor","this","_maxAttempts","_nodeAccountIds","List","transactionNodeIds","_signOnDemand","_minBackoff","_maxBackoff","_operator","_requestTimeout","_grpcDeadline","_logger","nodeAccountIds","isEmpty","setLocked","list","setNodeAccountIds","nodeIds","setList","maxRetries","console","warn","maxAttempts","setMaxRetries","setMaxAttempts","grpcDeadline","setGrpcDeadline","setMinBackoff","minBackoff","setMaxBackoff","maxBackoff","_beforeExecute","client","_makeRequestAsync","_mapStatusError","request","response","nodeId","_mapResponse","nodeAccountId","_execute","channel","_getTransactionId","_getLogId","_requestToBytes","_responseToBytes","_shouldRetry","_shouldRetryExceptionally","error","GrpcServiceError","status","_code","GrpcStatus","Timeout","DeadlineExceeded","Unavailable","ResourceExhausted","GrpcWeb","Internal","test","message","_setOperatorWith","accountId","publicKey","transactionSigner","executeWithSigner","signer","call","isBatchedAndNotBatchTransaction","execute","requestTimeout","isLocalNode","network","startTime","Date","now","persistentError","length","map","toString","some","includes","displayNodeAccountIds","slice","join","isSingleNode","attempt","MaxAttemptsOrTimeoutError","current","node","_network","getNode","advance","logId","debug","address","getChannel","isHealthy","isLastNode","index","isTransactionReceiptOrRecordRequest","delayForAttempt","promises","push","Promise","_","reject","setTimeout","trace","hex.encode","race","err","_fromResponse","JSON","stringify","HttpError","increaseBackoff","decreaseBackoff","shouldRetry","Status","Ok","Success","toBytes","setLogger","logger","resolve","ms","Math","min","floor","pow"],"mappings":"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"}
@@ -8,6 +8,7 @@ exports.default = void 0;
8
8
  exports.encodeRequest = encodeRequest;
9
9
  var HieroProto = _interopRequireWildcard(require("@hashgraph/proto"));
10
10
  var utf8 = _interopRequireWildcard(require("../encoding/utf8.cjs"));
11
+ var _ClientConstants = require("../constants/ClientConstants.cjs");
11
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
13
  // SPDX-License-Identifier: Apache-2.0
13
14
 
@@ -22,8 +23,9 @@ const {
22
23
  class Channel {
23
24
  /**
24
25
  * @protected
26
+ * @param {number} [grpcDeadline] - The gRPC deadline in milliseconds
25
27
  */
26
- constructor() {
28
+ constructor(grpcDeadline = _ClientConstants.DEFAULT_GRPC_DEADLINE) {
27
29
  /**
28
30
  * @protected
29
31
  * @type {?HieroProto.proto.CryptoService}
@@ -83,6 +85,28 @@ class Channel {
83
85
  * @type {?HieroProto.proto.AddressBookService}
84
86
  */
85
87
  this._addressBook = null;
88
+
89
+ /**
90
+ * @protected
91
+ * @type {number}
92
+ */
93
+ this._grpcDeadline = grpcDeadline;
94
+ }
95
+
96
+ /**
97
+ * Set the gRPC deadline for this channel
98
+ * @param {number} deadline - The deadline in milliseconds, or null to clear
99
+ */
100
+ setGrpcDeadline(deadline) {
101
+ this._grpcDeadline = deadline;
102
+ }
103
+
104
+ /**
105
+ * Get the gRPC deadline for this channel
106
+ * @returns {number}
107
+ */
108
+ get grpcDeadline() {
109
+ return this._grpcDeadline;
86
110
  }
87
111
 
88
112
  /**
@@ -15,6 +15,11 @@ export function decodeUnaryResponse(data: ArrayBuffer, byteOffset?: number, byte
15
15
  * @abstract
16
16
  */
17
17
  export default class Channel {
18
+ /**
19
+ * @protected
20
+ * @param {number} [grpcDeadline] - The gRPC deadline in milliseconds
21
+ */
22
+ protected constructor();
18
23
  /**
19
24
  * @protected
20
25
  * @type {?HieroProto.proto.CryptoService}
@@ -65,6 +70,21 @@ export default class Channel {
65
70
  * @type {?HieroProto.proto.AddressBookService}
66
71
  */
67
72
  protected _addressBook: HieroProto.proto.AddressBookService | null;
73
+ /**
74
+ * @protected
75
+ * @type {number}
76
+ */
77
+ protected _grpcDeadline: number;
78
+ /**
79
+ * Set the gRPC deadline for this channel
80
+ * @param {number} deadline - The deadline in milliseconds, or null to clear
81
+ */
82
+ setGrpcDeadline(deadline: number): void;
83
+ /**
84
+ * Get the gRPC deadline for this channel
85
+ * @returns {number}
86
+ */
87
+ get grpcDeadline(): number;
68
88
  /**
69
89
  * @abstract
70
90
  * @returns {void}
@@ -1,2 +1,2 @@
1
- import*as e from"@hashgraph/proto";import{decode as t}from"../encoding/utf8.js";const{proto:r}=e;class n{constructor(){this._crypto=null,this._smartContract=null,this._file=null,this._consensus=null,this._freeze=null,this._network=null,this._token=null,this._schedule=null,this._util=null,this._addressBook=null}close(){throw new Error("not implemented")}get crypto(){return null!=this._crypto||(this._crypto=r.CryptoService.create(this._createUnaryClient("CryptoService"))),this._crypto}get smartContract(){return null!=this._smartContract||(this._smartContract=r.SmartContractService.create(this._createUnaryClient("SmartContractService"))),this._smartContract}get file(){return null!=this._file||(this._file=r.FileService.create(this._createUnaryClient("FileService"))),this._file}get consensus(){return null!=this._consensus||(this._consensus=r.ConsensusService.create(this._createUnaryClient("ConsensusService"))),this._consensus}get freeze(){return null!=this._freeze||(this._freeze=r.FreezeService.create(this._createUnaryClient("FreezeService"))),this._freeze}get network(){return null!=this._network||(this._network=r.NetworkService.create(this._createUnaryClient("NetworkService"))),this._network}get token(){return null!=this._token||(this._token=r.TokenService.create(this._createUnaryClient("TokenService"))),this._token}get schedule(){return null!=this._schedule||(this._schedule=r.ScheduleService.create(this._createUnaryClient("ScheduleService"))),this._schedule}get util(){return null!=this._util||(this._util=r.UtilService.create(this._createUnaryClient("UtilService"))),this._util}get addressBook(){return null!=this._addressBook||(this._addressBook=r.AddressBookService.create(this._createUnaryClient("AddressBookService"))),this._addressBook}_createUnaryClient(e){throw new Error("not implemented")}}function s(e){const t=new ArrayBuffer(e.byteLength+5);return new DataView(t,1,4).setUint32(0,e.length),new Uint8Array(t,5).set(e),t}function i(e,r=0,n=e.byteLength){const s=new DataView(e,r,n);let i=0,o=null,l=0;for(;i<s.byteLength;){const r=s.getUint8(i+0)>>7,n=s.getUint32(i+1),c=i+5;if(c+n>s.byteLength)throw new Error("(BUG) unexpected frame length past the boundary");const a=new Uint8Array(e,s.byteOffset+c,n);if(0===r){if(null!=o)throw new Error("(BUG) unexpectedly received more than one data frame");o=a}else{if(1!==r)throw new Error(`(BUG) unexpected frame type: ${r}`);{const e=t(a),[r,n]=e.split(":");if("grpc-status"!==r)throw new Error(`(BUG) unhandled trailer, ${e}`);l=parseInt(n)}}i+=n+5}if(0!==l)throw new Error(`(BUG) unhandled grpc-status: ${l}`);if(null==o)throw new Error("(BUG) unexpectedly received no response");return o}export{i as decodeUnaryResponse,n as default,s as encodeRequest};
1
+ import*as e from"@hashgraph/proto";import{decode as t}from"../encoding/utf8.js";import{DEFAULT_GRPC_DEADLINE as r}from"../constants/ClientConstants.js";const{proto:n}=e;class s{constructor(e=r){this._crypto=null,this._smartContract=null,this._file=null,this._consensus=null,this._freeze=null,this._network=null,this._token=null,this._schedule=null,this._util=null,this._addressBook=null,this._grpcDeadline=e}setGrpcDeadline(e){this._grpcDeadline=e}get grpcDeadline(){return this._grpcDeadline}close(){throw new Error("not implemented")}get crypto(){return null!=this._crypto||(this._crypto=n.CryptoService.create(this._createUnaryClient("CryptoService"))),this._crypto}get smartContract(){return null!=this._smartContract||(this._smartContract=n.SmartContractService.create(this._createUnaryClient("SmartContractService"))),this._smartContract}get file(){return null!=this._file||(this._file=n.FileService.create(this._createUnaryClient("FileService"))),this._file}get consensus(){return null!=this._consensus||(this._consensus=n.ConsensusService.create(this._createUnaryClient("ConsensusService"))),this._consensus}get freeze(){return null!=this._freeze||(this._freeze=n.FreezeService.create(this._createUnaryClient("FreezeService"))),this._freeze}get network(){return null!=this._network||(this._network=n.NetworkService.create(this._createUnaryClient("NetworkService"))),this._network}get token(){return null!=this._token||(this._token=n.TokenService.create(this._createUnaryClient("TokenService"))),this._token}get schedule(){return null!=this._schedule||(this._schedule=n.ScheduleService.create(this._createUnaryClient("ScheduleService"))),this._schedule}get util(){return null!=this._util||(this._util=n.UtilService.create(this._createUnaryClient("UtilService"))),this._util}get addressBook(){return null!=this._addressBook||(this._addressBook=n.AddressBookService.create(this._createUnaryClient("AddressBookService"))),this._addressBook}_createUnaryClient(e){throw new Error("not implemented")}}function i(e){const t=new ArrayBuffer(e.byteLength+5);return new DataView(t,1,4).setUint32(0,e.length),new Uint8Array(t,5).set(e),t}function l(e,r=0,n=e.byteLength){const s=new DataView(e,r,n);let i=0,l=null,o=0;for(;i<s.byteLength;){const r=s.getUint8(i+0)>>7,n=s.getUint32(i+1),c=i+5;if(c+n>s.byteLength)throw new Error("(BUG) unexpected frame length past the boundary");const a=new Uint8Array(e,s.byteOffset+c,n);if(0===r){if(null!=l)throw new Error("(BUG) unexpectedly received more than one data frame");l=a}else{if(1!==r)throw new Error(`(BUG) unexpected frame type: ${r}`);{const e=t(a),[r,n]=e.split(":");if("grpc-status"!==r)throw new Error(`(BUG) unhandled trailer, ${e}`);o=parseInt(n)}}i+=n+5}if(0!==o)throw new Error(`(BUG) unhandled grpc-status: ${o}`);if(null==l)throw new Error("(BUG) unexpectedly received no response");return l}export{l as decodeUnaryResponse,s as default,i as encodeRequest};
2
2
  //# sourceMappingURL=Channel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Channel.js","sources":["../../src/channel/Channel.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport * as HieroProto from \"@hashgraph/proto\";\nimport * as utf8 from \"../encoding/utf8.js\";\n\nconst { proto } = HieroProto;\n\n/**\n * @internal\n * @abstract\n */\nexport default class Channel {\n /**\n * @protected\n */\n constructor() {\n /**\n * @protected\n * @type {?HieroProto.proto.CryptoService}\n */\n this._crypto = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.SmartContractService}\n */\n this._smartContract = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.FileService}\n */\n this._file = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.ConsensusService}\n */\n this._consensus = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.FreezeService}\n */\n this._freeze = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.NetworkService}\n */\n this._network = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.TokenService}\n */\n this._token = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.ScheduleService}\n */\n this._schedule = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.UtilService}\n */\n this._util = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.AddressBookService}\n */\n this._addressBook = null;\n }\n\n /**\n * @abstract\n * @returns {void}\n */\n close() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * @returns {HieroProto.proto.CryptoService}\n */\n get crypto() {\n if (this._crypto != null) {\n return this._crypto;\n }\n\n this._crypto = proto.CryptoService.create(\n this._createUnaryClient(\"CryptoService\"),\n );\n\n return this._crypto;\n }\n\n /**\n * @returns {HieroProto.proto.SmartContractService}\n */\n get smartContract() {\n if (this._smartContract != null) {\n return this._smartContract;\n }\n\n this._smartContract = proto.SmartContractService.create(\n this._createUnaryClient(\"SmartContractService\"),\n );\n\n return this._smartContract;\n }\n\n /**\n * @returns {HieroProto.proto.FileService}\n */\n get file() {\n if (this._file != null) {\n return this._file;\n }\n\n this._file = proto.FileService.create(\n this._createUnaryClient(\"FileService\"),\n );\n\n return this._file;\n }\n\n /**\n * @returns {HieroProto.proto.ConsensusService}\n */\n get consensus() {\n if (this._consensus != null) {\n return this._consensus;\n }\n\n this._consensus = proto.ConsensusService.create(\n this._createUnaryClient(\"ConsensusService\"),\n );\n\n return this._consensus;\n }\n\n /**\n * @returns {HieroProto.proto.FreezeService}\n */\n get freeze() {\n if (this._freeze != null) {\n return this._freeze;\n }\n\n this._freeze = proto.FreezeService.create(\n this._createUnaryClient(\"FreezeService\"),\n );\n\n return this._freeze;\n }\n\n /**\n * @returns {HieroProto.proto.NetworkService}\n */\n get network() {\n if (this._network != null) {\n return this._network;\n }\n\n this._network = proto.NetworkService.create(\n this._createUnaryClient(\"NetworkService\"),\n );\n\n return this._network;\n }\n\n /**\n * @returns {HieroProto.proto.TokenService}\n */\n get token() {\n if (this._token != null) {\n return this._token;\n }\n\n this._token = proto.TokenService.create(\n this._createUnaryClient(\"TokenService\"),\n );\n\n return this._token;\n }\n\n /**\n * @returns {HieroProto.proto.ScheduleService}\n */\n get schedule() {\n if (this._schedule != null) {\n return this._schedule;\n }\n\n this._schedule = proto.ScheduleService.create(\n this._createUnaryClient(\"ScheduleService\"),\n );\n\n return this._schedule;\n }\n\n /**\n * @returns {HieroProto.proto.UtilService}\n */\n get util() {\n if (this._util != null) {\n return this._util;\n }\n\n this._util = proto.UtilService.create(\n this._createUnaryClient(\"UtilService\"),\n );\n\n return this._util;\n }\n\n /**\n * @returns {HieroProto.proto.AddressBookService}\n */\n get addressBook() {\n if (this._addressBook != null) {\n return this._addressBook;\n }\n\n this._addressBook = proto.AddressBookService.create(\n this._createUnaryClient(\"AddressBookService\"),\n );\n\n return this._addressBook;\n }\n\n /**\n * @abstract\n * @protected\n * @param {string} serviceName\n * @returns {import(\"protobufjs\").RPCImpl}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _createUnaryClient(serviceName) {\n throw new Error(\"not implemented\");\n }\n}\n\n// grpc-web+proto is a series of data or trailer frames\n\n// a frame is identified by a single byte (0 = data or 1 = trailer) followed by 4 bytes for the\n// length of the frame, followed by the frame data\n\n/**\n * @param {Uint8Array} data\n * @returns {ArrayBuffer}\n */\nexport function encodeRequest(data) {\n // for our requests, we want to transfer a single data frame\n\n const frame = new ArrayBuffer(data.byteLength + 5);\n\n // the frame type (data) is zero and can be left default-initialized\n\n // the length of the frame data\n new DataView(frame, 1, 4).setUint32(0, data.length);\n\n // copy in the frame data\n new Uint8Array(frame, 5).set(data);\n\n return frame;\n}\n\n/**\n * @param {ArrayBuffer} data\n * @param {number} byteOffset\n * @param {number} byteLength\n * @returns {Uint8Array}\n */\nexport function decodeUnaryResponse(\n data,\n byteOffset = 0,\n byteLength = data.byteLength,\n) {\n const dataView = new DataView(data, byteOffset, byteLength);\n let dataOffset = 0;\n\n /** @type {?Uint8Array} */\n let unaryResponse = null;\n\n // 0 = successful\n let status = 0;\n\n while (dataOffset < dataView.byteLength) {\n const frameByte = dataView.getUint8(dataOffset + 0);\n const frameType = frameByte >> 7;\n const frameByteLength = dataView.getUint32(dataOffset + 1);\n const frameOffset = dataOffset + 5; // offset from the start of the dataView\n if (frameOffset + frameByteLength > dataView.byteLength) {\n throw new Error(\"(BUG) unexpected frame length past the boundary\");\n }\n const frameData = new Uint8Array(\n data,\n dataView.byteOffset + frameOffset,\n frameByteLength,\n );\n\n if (frameType === 0) {\n if (unaryResponse != null) {\n throw new Error(\n \"(BUG) unexpectedly received more than one data frame\",\n );\n }\n\n unaryResponse = frameData;\n } else if (frameType === 1) {\n const trailer = utf8.decode(frameData);\n const [trailerName, trailerValue] = trailer.split(\":\");\n\n if (trailerName === \"grpc-status\") {\n status = parseInt(trailerValue);\n } else {\n throw new Error(`(BUG) unhandled trailer, ${trailer}`);\n }\n } else {\n throw new Error(`(BUG) unexpected frame type: ${frameType}`);\n }\n\n dataOffset += frameByteLength + 5;\n }\n\n if (status !== 0) {\n throw new Error(`(BUG) unhandled grpc-status: ${status}`);\n }\n\n if (unaryResponse == null) {\n throw new Error(\"(BUG) unexpectedly received no response\");\n }\n\n return unaryResponse;\n}\n"],"names":["proto","HieroProto","Channel","constructor","this","_crypto","_smartContract","_file","_consensus","_freeze","_network","_token","_schedule","_util","_addressBook","close","Error","crypto","CryptoService","create","_createUnaryClient","smartContract","SmartContractService","file","FileService","consensus","ConsensusService","freeze","FreezeService","network","NetworkService","token","TokenService","schedule","ScheduleService","util","UtilService","addressBook","AddressBookService","serviceName","encodeRequest","data","frame","ArrayBuffer","byteLength","DataView","setUint32","length","Uint8Array","set","decodeUnaryResponse","byteOffset","dataView","dataOffset","unaryResponse","status","frameType","getUint8","frameByteLength","getUint32","frameOffset","frameData","trailer","utf8.decode","trailerName","trailerValue","split","parseInt"],"mappings":"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"}
1
+ {"version":3,"file":"Channel.js","sources":["../../src/channel/Channel.js"],"sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\nimport * as HieroProto from \"@hashgraph/proto\";\nimport * as utf8 from \"../encoding/utf8.js\";\nimport { DEFAULT_GRPC_DEADLINE } from \"../constants/ClientConstants.js\";\n\nconst { proto } = HieroProto;\n\n/**\n * @internal\n * @abstract\n */\nexport default class Channel {\n /**\n * @protected\n * @param {number} [grpcDeadline] - The gRPC deadline in milliseconds\n */\n constructor(grpcDeadline = DEFAULT_GRPC_DEADLINE) {\n /**\n * @protected\n * @type {?HieroProto.proto.CryptoService}\n */\n this._crypto = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.SmartContractService}\n */\n this._smartContract = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.FileService}\n */\n this._file = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.ConsensusService}\n */\n this._consensus = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.FreezeService}\n */\n this._freeze = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.NetworkService}\n */\n this._network = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.TokenService}\n */\n this._token = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.ScheduleService}\n */\n this._schedule = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.UtilService}\n */\n this._util = null;\n\n /**\n * @protected\n * @type {?HieroProto.proto.AddressBookService}\n */\n this._addressBook = null;\n\n /**\n * @protected\n * @type {number}\n */\n this._grpcDeadline = grpcDeadline;\n }\n\n /**\n * Set the gRPC deadline for this channel\n * @param {number} deadline - The deadline in milliseconds, or null to clear\n */\n setGrpcDeadline(deadline) {\n this._grpcDeadline = deadline;\n }\n\n /**\n * Get the gRPC deadline for this channel\n * @returns {number}\n */\n get grpcDeadline() {\n return this._grpcDeadline;\n }\n\n /**\n * @abstract\n * @returns {void}\n */\n close() {\n throw new Error(\"not implemented\");\n }\n\n /**\n * @returns {HieroProto.proto.CryptoService}\n */\n get crypto() {\n if (this._crypto != null) {\n return this._crypto;\n }\n\n this._crypto = proto.CryptoService.create(\n this._createUnaryClient(\"CryptoService\"),\n );\n\n return this._crypto;\n }\n\n /**\n * @returns {HieroProto.proto.SmartContractService}\n */\n get smartContract() {\n if (this._smartContract != null) {\n return this._smartContract;\n }\n\n this._smartContract = proto.SmartContractService.create(\n this._createUnaryClient(\"SmartContractService\"),\n );\n\n return this._smartContract;\n }\n\n /**\n * @returns {HieroProto.proto.FileService}\n */\n get file() {\n if (this._file != null) {\n return this._file;\n }\n\n this._file = proto.FileService.create(\n this._createUnaryClient(\"FileService\"),\n );\n\n return this._file;\n }\n\n /**\n * @returns {HieroProto.proto.ConsensusService}\n */\n get consensus() {\n if (this._consensus != null) {\n return this._consensus;\n }\n\n this._consensus = proto.ConsensusService.create(\n this._createUnaryClient(\"ConsensusService\"),\n );\n\n return this._consensus;\n }\n\n /**\n * @returns {HieroProto.proto.FreezeService}\n */\n get freeze() {\n if (this._freeze != null) {\n return this._freeze;\n }\n\n this._freeze = proto.FreezeService.create(\n this._createUnaryClient(\"FreezeService\"),\n );\n\n return this._freeze;\n }\n\n /**\n * @returns {HieroProto.proto.NetworkService}\n */\n get network() {\n if (this._network != null) {\n return this._network;\n }\n\n this._network = proto.NetworkService.create(\n this._createUnaryClient(\"NetworkService\"),\n );\n\n return this._network;\n }\n\n /**\n * @returns {HieroProto.proto.TokenService}\n */\n get token() {\n if (this._token != null) {\n return this._token;\n }\n\n this._token = proto.TokenService.create(\n this._createUnaryClient(\"TokenService\"),\n );\n\n return this._token;\n }\n\n /**\n * @returns {HieroProto.proto.ScheduleService}\n */\n get schedule() {\n if (this._schedule != null) {\n return this._schedule;\n }\n\n this._schedule = proto.ScheduleService.create(\n this._createUnaryClient(\"ScheduleService\"),\n );\n\n return this._schedule;\n }\n\n /**\n * @returns {HieroProto.proto.UtilService}\n */\n get util() {\n if (this._util != null) {\n return this._util;\n }\n\n this._util = proto.UtilService.create(\n this._createUnaryClient(\"UtilService\"),\n );\n\n return this._util;\n }\n\n /**\n * @returns {HieroProto.proto.AddressBookService}\n */\n get addressBook() {\n if (this._addressBook != null) {\n return this._addressBook;\n }\n\n this._addressBook = proto.AddressBookService.create(\n this._createUnaryClient(\"AddressBookService\"),\n );\n\n return this._addressBook;\n }\n\n /**\n * @abstract\n * @protected\n * @param {string} serviceName\n * @returns {import(\"protobufjs\").RPCImpl}\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n _createUnaryClient(serviceName) {\n throw new Error(\"not implemented\");\n }\n}\n\n// grpc-web+proto is a series of data or trailer frames\n\n// a frame is identified by a single byte (0 = data or 1 = trailer) followed by 4 bytes for the\n// length of the frame, followed by the frame data\n\n/**\n * @param {Uint8Array} data\n * @returns {ArrayBuffer}\n */\nexport function encodeRequest(data) {\n // for our requests, we want to transfer a single data frame\n\n const frame = new ArrayBuffer(data.byteLength + 5);\n\n // the frame type (data) is zero and can be left default-initialized\n\n // the length of the frame data\n new DataView(frame, 1, 4).setUint32(0, data.length);\n\n // copy in the frame data\n new Uint8Array(frame, 5).set(data);\n\n return frame;\n}\n\n/**\n * @param {ArrayBuffer} data\n * @param {number} byteOffset\n * @param {number} byteLength\n * @returns {Uint8Array}\n */\nexport function decodeUnaryResponse(\n data,\n byteOffset = 0,\n byteLength = data.byteLength,\n) {\n const dataView = new DataView(data, byteOffset, byteLength);\n let dataOffset = 0;\n\n /** @type {?Uint8Array} */\n let unaryResponse = null;\n\n // 0 = successful\n let status = 0;\n\n while (dataOffset < dataView.byteLength) {\n const frameByte = dataView.getUint8(dataOffset + 0);\n const frameType = frameByte >> 7;\n const frameByteLength = dataView.getUint32(dataOffset + 1);\n const frameOffset = dataOffset + 5; // offset from the start of the dataView\n if (frameOffset + frameByteLength > dataView.byteLength) {\n throw new Error(\"(BUG) unexpected frame length past the boundary\");\n }\n const frameData = new Uint8Array(\n data,\n dataView.byteOffset + frameOffset,\n frameByteLength,\n );\n\n if (frameType === 0) {\n if (unaryResponse != null) {\n throw new Error(\n \"(BUG) unexpectedly received more than one data frame\",\n );\n }\n\n unaryResponse = frameData;\n } else if (frameType === 1) {\n const trailer = utf8.decode(frameData);\n const [trailerName, trailerValue] = trailer.split(\":\");\n\n if (trailerName === \"grpc-status\") {\n status = parseInt(trailerValue);\n } else {\n throw new Error(`(BUG) unhandled trailer, ${trailer}`);\n }\n } else {\n throw new Error(`(BUG) unexpected frame type: ${frameType}`);\n }\n\n dataOffset += frameByteLength + 5;\n }\n\n if (status !== 0) {\n throw new Error(`(BUG) unhandled grpc-status: ${status}`);\n }\n\n if (unaryResponse == null) {\n throw new Error(\"(BUG) unexpectedly received no response\");\n }\n\n return unaryResponse;\n}\n"],"names":["proto","HieroProto","Channel","constructor","grpcDeadline","DEFAULT_GRPC_DEADLINE","this","_crypto","_smartContract","_file","_consensus","_freeze","_network","_token","_schedule","_util","_addressBook","_grpcDeadline","setGrpcDeadline","deadline","close","Error","crypto","CryptoService","create","_createUnaryClient","smartContract","SmartContractService","file","FileService","consensus","ConsensusService","freeze","FreezeService","network","NetworkService","token","TokenService","schedule","ScheduleService","util","UtilService","addressBook","AddressBookService","serviceName","encodeRequest","data","frame","ArrayBuffer","byteLength","DataView","setUint32","length","Uint8Array","set","decodeUnaryResponse","byteOffset","dataView","dataOffset","unaryResponse","status","frameType","getUint8","frameByteLength","getUint32","frameOffset","frameData","trailer","utf8.decode","trailerName","trailerValue","split","parseInt"],"mappings":"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"}
@@ -9,6 +9,8 @@ var base64 = _interopRequireWildcard(require("../encoding/base64.native.cjs"));
9
9
  var _HttpError = _interopRequireDefault(require("../http/HttpError.cjs"));
10
10
  var _HttpStatus = _interopRequireDefault(require("../http/HttpStatus.cjs"));
11
11
  var _version = require("../version.cjs");
12
+ var _GrpcServiceError = _interopRequireDefault(require("../grpc/GrpcServiceError.cjs"));
13
+ var _GrpcStatus = _interopRequireDefault(require("../grpc/GrpcStatus.cjs"));
12
14
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
15
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
16
  // SPDX-License-Identifier: Apache-2.0
@@ -16,15 +18,25 @@ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r
16
18
  class NativeChannel extends _Channel.default {
17
19
  /**
18
20
  * @param {string} address
21
+ * @param {number=} grpcDeadline
19
22
  */
20
- constructor(address) {
21
- super();
23
+ constructor(address, grpcDeadline) {
24
+ super(grpcDeadline);
22
25
 
23
26
  /**
24
27
  * @type {string}
25
28
  * @private
26
29
  */
27
30
  this._address = address;
31
+
32
+ /**
33
+ * Flag indicating if the connection is ready (health check has passed)
34
+ * Set to true after the first successful health check
35
+ *
36
+ * @type {boolean}
37
+ * @private
38
+ */
39
+ this._isReady = false;
28
40
  }
29
41
 
30
42
  /**
@@ -35,6 +47,78 @@ class NativeChannel extends _Channel.default {
35
47
  // do nothing
36
48
  }
37
49
 
50
+ /**
51
+ * Check if the gRPC-Web proxy is reachable and healthy
52
+ * Performs a POST request and verifies the response has gRPC-Web headers,
53
+ * which indicates the proxy is running and processing gRPC requests.
54
+ * Results are cached per address for the entire lifecycle.
55
+ *
56
+ * @param {Date} deadline - Deadline for the health check
57
+ * @returns {Promise<void>}
58
+ * @private
59
+ */
60
+ async _waitForReady(deadline) {
61
+ // Check if we've already validated this address
62
+ if (this._isReady) {
63
+ return; // Health check already passed for this address
64
+ }
65
+ const shouldUseHttps = !(this._address.includes("localhost") || this._address.includes("127.0.0.1"));
66
+ const address = shouldUseHttps ? `https://${this._address}` : `http://${this._address}`;
67
+
68
+ // Calculate remaining time until deadline
69
+ const timeoutMs = deadline.getTime() - Date.now();
70
+ if (timeoutMs <= 0) {
71
+ throw new _GrpcServiceError.default(_GrpcStatus.default.Timeout);
72
+ }
73
+ const abortController = new AbortController();
74
+ const timeoutId = setTimeout(() => abortController.abort(), timeoutMs);
75
+ try {
76
+ // Make a POST request to verify the gRPC-Web proxy is running
77
+ // We use a minimal gRPC-Web compatible request
78
+ //eslint-disable-next-line n/no-unsupported-features/node-builtins
79
+ const response = await fetch(address, {
80
+ method: "POST",
81
+ headers: {
82
+ "content-type": "application/grpc-web-text",
83
+ "x-user-agent": `${_version.SDK_NAME}/${_version.SDK_VERSION}`,
84
+ "x-grpc-web": "1"
85
+ },
86
+ body: base64.encode(new Uint8Array(0)),
87
+ // Empty body for health check
88
+ signal: abortController.signal
89
+ });
90
+ clearTimeout(timeoutId);
91
+
92
+ // Check if response is successful (200) and has gRPC headers
93
+ if (response.status === 200) {
94
+ const grpcStatus = response.headers.get("grpc-status");
95
+ const grpcMessage = response.headers.get("grpc-message");
96
+
97
+ // If gRPC headers exist, the proxy is running and processing requests
98
+ if (grpcStatus != null || grpcMessage != null) {
99
+ // Mark this connection as ready
100
+ this._isReady = true;
101
+ return; // Healthy - gRPC-Web proxy is responding
102
+ }
103
+ }
104
+
105
+ // If we get here, either status isn't 200 or no gRPC headers present
106
+ // This means the proxy might not be configured correctly or not running
107
+ throw new _GrpcServiceError.default(_GrpcStatus.default.Unavailable);
108
+ } catch (error) {
109
+ clearTimeout(timeoutId);
110
+ if (error instanceof Error && error.name === "AbortError") {
111
+ throw new _GrpcServiceError.default(_GrpcStatus.default.Timeout);
112
+ }
113
+ if (error instanceof _GrpcServiceError.default) {
114
+ throw error;
115
+ }
116
+
117
+ // Network error - server is not reachable
118
+ throw new _GrpcServiceError.default(_GrpcStatus.default.Unavailable);
119
+ }
120
+ }
121
+
38
122
  /**
39
123
  * @override
40
124
  * @protected
@@ -44,7 +128,13 @@ class NativeChannel extends _Channel.default {
44
128
  _createUnaryClient(serviceName) {
45
129
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
46
130
  return async (method, requestData, callback) => {
131
+ // Calculate deadline for connection check
132
+ const deadline = new Date();
133
+ const milliseconds = this._grpcDeadline;
134
+ deadline.setMilliseconds(deadline.getMilliseconds() + milliseconds);
47
135
  try {
136
+ // Wait for connection to be ready (similar to gRPC waitForReady)
137
+ await this._waitForReady(deadline);
48
138
  const data = base64.encode(new Uint8Array((0, _Channel.encodeRequest)(requestData)));
49
139
  const shouldUseHttps = !(this._address.includes("localhost") || this._address.includes("127.0.0.1"));
50
140
  const address = shouldUseHttps ? `https://${this._address}` : `http://${this._address}`;
@@ -89,6 +179,10 @@ class NativeChannel extends _Channel.default {
89
179
  responseBuffer.buffer, responseBuffer.byteOffset, responseBuffer.byteLength);
90
180
  callback(null, unaryResponse);
91
181
  } catch (error) {
182
+ if (error instanceof _GrpcServiceError.default) {
183
+ callback(error, null);
184
+ return;
185
+ }
92
186
  callback(/** @type {Error} */error, null);
93
187
  }
94
188
  };