postchain-client 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -43,6 +43,8 @@ Create a Chromia client instance and configures it according to your needs.
43
43
  - `settings` (Object): A set of network settings to customize the behavior of the Chromia client.
44
44
  - `nodeUrlPool` (Optional): An array of URLs representing the nodes the client will send requests to. Use this if you know the specific nodes that will handle the client requests. These nodes can either be local nodes or belong to the same cluster as the targeted blockchain.
45
45
  - `directoryNodeUrlPool` (Optional): An array of URLs representing nodes in the system cluster, where the directory chain is located. The client will automatically discover every node running the targeted application by querying the directory chain. This can be useful when the client needs to automatically adapt to updates to the nodes within the cluster where the blockchain is located."
46
+ - `blockedNodeUrlSubstrings` (Optional): Opt-in node URL filtering. If configured, URLs containing any listed substring are excluded (case-insensitive). By default this is disabled, so existing behavior is unchanged.
47
+ - `nodeUrlFilter` (Optional): Opt-in custom predicate `(url: string) => boolean` used to accept/reject node URLs. If both `blockedNodeUrlSubstrings` and `nodeUrlFilter` are set, a URL is used only when it passes both filters.
46
48
  - `blockchainRid` (Optional): Resource Identifier (Rid) of the targeted blockchain. This is a unique identifier for the specific blockchain.
47
49
  - `blockchainIid` (Optional): Instance Identifier (Iid) of the targeted blockchain. The directory chain always has Iid 0.
48
50
  - `statusPollInterval` (Optional): Interval (in milliseconds) at which the client will poll the status after posting a transaction.
@@ -54,6 +56,12 @@ Create a Chromia client instance and configures it according to your needs.
54
56
  - `unreachableDuration` (Optional): Duration (in milliseconds) that an endpoint should remain unreachable before reattempting. Defaults to 30000 ms.
55
57
  - `useStickyNode`(Optional): A boolean that will make sure that on succefull requests to a node, the client will continue using this node unless it starts failing.
56
58
 
59
+ ### Optional node URL filtering (opt-in)
60
+
61
+ Node URL filtering is disabled by default for backward compatibility. Existing users do not need to change anything.
62
+
63
+ If you opt in by configuring `blockedNodeUrlSubstrings` and/or `nodeUrlFilter`, filtering is applied consistently to direct node pools, directory node pools, and directory-discovered blockchain API URLs before failover candidates are used.
64
+
57
65
  ### Returns
58
66
 
59
67
  A promise that resolves to the configured Chromia client instance.
@@ -1120,7 +1120,7 @@ var utils$1 = {};
1120
1120
  var errors = {};
1121
1121
 
1122
1122
  Object.defineProperty(errors, "__esModule", { value: true });
1123
- errors.GetBridFromChainException = errors.SerializedTransactionFormatException = errors.InvalidTxRidException = errors.UnexpectedStatusError = errors.TxRejectedError = errors.GetTransactionRidException = errors.InvalidTransactionFormatException = errors.DirectoryNodeUrlPoolException = errors.BlockchainUrlUndefinedException = errors.MissingNodeUrlError = errors.MissingBlockchainIdentifierError = errors.MissingPubKeyError = void 0;
1123
+ errors.GetBridFromChainException = errors.SerializedTransactionFormatException = errors.InvalidTxRidException = errors.UnexpectedStatusError = errors.TxRejectedError = errors.GetTransactionRidException = errors.InvalidTransactionFormatException = errors.FilteredNodeUrlPoolEmptyError = errors.DirectoryNodeUrlPoolException = errors.BlockchainUrlUndefinedException = errors.MissingNodeUrlError = errors.MissingBlockchainIdentifierError = errors.MissingPubKeyError = void 0;
1124
1124
  const customError_1 = customError;
1125
1125
  const formatter_1$1 = formatter;
1126
1126
  class MissingPubKeyError extends customError_1.CustomError {
@@ -1154,6 +1154,12 @@ class DirectoryNodeUrlPoolException extends customError_1.CustomError {
1154
1154
  }
1155
1155
  }
1156
1156
  errors.DirectoryNodeUrlPoolException = DirectoryNodeUrlPoolException;
1157
+ class FilteredNodeUrlPoolEmptyError extends customError_1.CustomError {
1158
+ constructor(poolName) {
1159
+ super(`All node URLs were filtered out for pool "${poolName}". Update node URL filters or pool configuration.`, 400);
1160
+ }
1161
+ }
1162
+ errors.FilteredNodeUrlPoolEmptyError = FilteredNodeUrlPoolEmptyError;
1157
1163
  class InvalidTransactionFormatException extends customError_1.CustomError {
1158
1164
  constructor() {
1159
1165
  super(`The transaction is not in the right format`, 400);
@@ -2481,23 +2487,9 @@ function requireUtils$1 () {
2481
2487
  responseTimeout: settings.responseTimeout,
2482
2488
  });
2483
2489
  }))();
2484
- return {
2485
- endpointPool,
2486
- nodeManager: nodeManager,
2487
- blockchainRid: blockchainRidToUse,
2488
- merkleHashVersion: (_e = settings.merkleHashVersion) !== null && _e !== void 0 ? _e : constants_1.MERKLE_HASH_VERSIONS.UNSET,
2489
- dappStatusPolling: setStatusPolling(settings.dappStatusPolling),
2490
- clusterAnchoringStatusPolling: setStatusPolling(settings.clusterAnchoringStatusPolling),
2491
- systemAnchoringStatusPolling: setStatusPolling(settings.systemAnchoringStatusPolling),
2492
- retryTransactionPolling: setRetryTransactionPolling(settings.retryTransactionPolling),
2493
- failoverStrategy: ((_f = settings.failOverConfig) === null || _f === void 0 ? void 0 : _f.strategy) || exports.defaultFailoverConfig.strategy,
2494
- attemptsPerEndpoint: ((_g = settings.failOverConfig) === null || _g === void 0 ? void 0 : _g.attemptsPerEndpoint) || exports.defaultFailoverConfig.attemptsPerEndpoint,
2495
- attemptInterval: ((_h = settings.failOverConfig) === null || _h === void 0 ? void 0 : _h.attemptInterval) || exports.defaultFailoverConfig.attemptInterval,
2496
- unreachableDuration: ((_j = settings.failOverConfig) === null || _j === void 0 ? void 0 : _j.unreachableDuration) || exports.defaultFailoverConfig.unreachableDuration,
2497
- directoryChainRid: settings.directoryChainRid || directoryChainRid,
2498
- connectTimeout: settings.connectTimeout,
2499
- responseTimeout: settings.responseTimeout,
2500
- };
2490
+ return Object.assign(Object.assign(Object.assign({ endpointPool, nodeManager: nodeManager }, (settings.blockedNodeUrlSubstrings !== undefined
2491
+ ? { blockedNodeUrlSubstrings: settings.blockedNodeUrlSubstrings }
2492
+ : {})), (settings.nodeUrlFilter !== undefined ? { nodeUrlFilter: settings.nodeUrlFilter } : {})), { blockchainRid: blockchainRidToUse, merkleHashVersion: (_e = settings.merkleHashVersion) !== null && _e !== void 0 ? _e : constants_1.MERKLE_HASH_VERSIONS.UNSET, dappStatusPolling: setStatusPolling(settings.dappStatusPolling), clusterAnchoringStatusPolling: setStatusPolling(settings.clusterAnchoringStatusPolling), systemAnchoringStatusPolling: setStatusPolling(settings.systemAnchoringStatusPolling), retryTransactionPolling: setRetryTransactionPolling(settings.retryTransactionPolling), failoverStrategy: ((_f = settings.failOverConfig) === null || _f === void 0 ? void 0 : _f.strategy) || exports.defaultFailoverConfig.strategy, attemptsPerEndpoint: ((_g = settings.failOverConfig) === null || _g === void 0 ? void 0 : _g.attemptsPerEndpoint) || exports.defaultFailoverConfig.attemptsPerEndpoint, attemptInterval: ((_h = settings.failOverConfig) === null || _h === void 0 ? void 0 : _h.attemptInterval) || exports.defaultFailoverConfig.attemptInterval, unreachableDuration: ((_j = settings.failOverConfig) === null || _j === void 0 ? void 0 : _j.unreachableDuration) || exports.defaultFailoverConfig.unreachableDuration, directoryChainRid: settings.directoryChainRid || directoryChainRid, connectTimeout: settings.connectTimeout, responseTimeout: settings.responseTimeout });
2501
2493
  });
2502
2494
  }
2503
2495
  function getMerkleHashVersionFromDapp(config) {
@@ -2523,7 +2515,7 @@ function requireUtils$1 () {
2523
2515
  return true;
2524
2516
  }
2525
2517
  function nodeDiscovery(_a) {
2526
- return __awaiter(this, arguments, void 0, function* ({ nodeManager, directoryEndpointPool, failOverConfig, blockchainRid, blockchainIid, connectTimeout, responseTimeout, }) {
2518
+ return __awaiter(this, arguments, void 0, function* ({ nodeManager, directoryEndpointPool, blockedNodeUrlSubstrings, nodeUrlFilter, failOverConfig, blockchainRid, blockchainIid, connectTimeout, responseTimeout, }) {
2527
2519
  if (directoryEndpointPool.length === 0) {
2528
2520
  throw new errors_2.DirectoryNodeUrlPoolException();
2529
2521
  }
@@ -2559,7 +2551,11 @@ function requireUtils$1 () {
2559
2551
  nodeUrlPool: (0, exports.getUrlsFromEndpoints)(directoryEndpointPool),
2560
2552
  blockchainRid: directoryBRID,
2561
2553
  });
2562
- return yield getBlockchainApiUrls(D1Client, (0, formatter_1.ensureBuffer)(blockchainRidToUse));
2554
+ const discoveredNodes = yield getBlockchainApiUrls(D1Client, (0, formatter_1.ensureBuffer)(blockchainRidToUse));
2555
+ return applyNodeUrlFilters(discoveredNodes, {
2556
+ blockedNodeUrlSubstrings,
2557
+ nodeUrlFilter,
2558
+ }, "discoveredNodeUrlPool");
2563
2559
  });
2564
2560
  }
2565
2561
  function getBlockchainApiUrls(directoryClient, blockchainRid) {
@@ -2702,14 +2698,21 @@ function requireUtils$1 () {
2702
2698
  return __awaiter(this, void 0, void 0, function* () {
2703
2699
  var _a;
2704
2700
  if (settings.directoryNodeUrlPool) {
2701
+ const directoryNodeUrlsOrNull = applyNodeUrlFilters(ensureArray(settings.directoryNodeUrlPool), settings, "directoryNodeUrlPool");
2702
+ if (directoryNodeUrlsOrNull === null) {
2703
+ throw new errors_2.DirectoryNodeUrlPoolException();
2704
+ }
2705
+ const directoryNodeUrls = directoryNodeUrlsOrNull;
2705
2706
  // If directoryNodeUrlPool is provided, use nodeDiscovery
2706
2707
  const nodeManager = (0, nodeManager_1.createNodeManager)({
2707
- nodeUrls: ensureArray(settings.directoryNodeUrlPool),
2708
+ nodeUrls: directoryNodeUrls,
2708
2709
  unavailableDuration: (_a = settings.failOverConfig) === null || _a === void 0 ? void 0 : _a.unreachableDuration,
2709
2710
  });
2710
2711
  const discoveredNodes = yield nodeDiscovery({
2711
2712
  nodeManager,
2712
- directoryEndpointPool: (0, exports.createEndpointObjects)(ensureArray(settings.directoryNodeUrlPool)),
2713
+ directoryEndpointPool: (0, exports.createEndpointObjects)(directoryNodeUrls),
2714
+ blockedNodeUrlSubstrings: settings.blockedNodeUrlSubstrings,
2715
+ nodeUrlFilter: settings.nodeUrlFilter,
2713
2716
  failOverConfig: settings.failOverConfig,
2714
2717
  blockchainRid: settings.blockchainRid,
2715
2718
  blockchainIid: settings.blockchainIid,
@@ -2720,11 +2723,11 @@ function requireUtils$1 () {
2720
2723
  }
2721
2724
  else if (typeof settings.nodeUrlPool === "string") {
2722
2725
  // If nodeUrlPool is a string, convert it to an array
2723
- return [settings.nodeUrlPool];
2726
+ return applyNodeUrlFilters([settings.nodeUrlPool], settings, "nodeUrlPool");
2724
2727
  }
2725
2728
  else if (Array.isArray(settings.nodeUrlPool)) {
2726
2729
  // If nodeUrlPool is already an array, use it as-is
2727
- return settings.nodeUrlPool;
2730
+ return applyNodeUrlFilters(settings.nodeUrlPool, settings, "nodeUrlPool");
2728
2731
  }
2729
2732
  else {
2730
2733
  // Default to an empty array if no valid configuration is provided
@@ -2732,11 +2735,37 @@ function requireUtils$1 () {
2732
2735
  }
2733
2736
  });
2734
2737
  }
2735
- function getSystemClient(directoryNodeUrlPool, directoryChainRid) {
2738
+ function applyNodeUrlFilters(nodeUrls, settings, poolName) {
2739
+ var _a;
2740
+ if (nodeUrls === null) {
2741
+ return null;
2742
+ }
2743
+ const hasBlockedSubstringsFilter = Array.isArray(settings.blockedNodeUrlSubstrings) &&
2744
+ settings.blockedNodeUrlSubstrings.length > 0;
2745
+ const hasNodeUrlFilter = typeof settings.nodeUrlFilter === "function";
2746
+ if (!hasBlockedSubstringsFilter && !hasNodeUrlFilter) {
2747
+ return nodeUrls;
2748
+ }
2749
+ const blockedSubstrings = ((_a = settings.blockedNodeUrlSubstrings) !== null && _a !== void 0 ? _a : [])
2750
+ .map(substring => substring.toLowerCase())
2751
+ .filter(substring => substring.length > 0);
2752
+ const filteredNodeUrls = nodeUrls.filter(url => {
2753
+ const isBlockedBySubstring = blockedSubstrings.some(substring => url.toLowerCase().includes(substring));
2754
+ const passesCustomFilter = settings.nodeUrlFilter ? settings.nodeUrlFilter(url) : true;
2755
+ return !isBlockedBySubstring && passesCustomFilter;
2756
+ });
2757
+ if (filteredNodeUrls.length === 0) {
2758
+ throw new errors_2.FilteredNodeUrlPoolEmptyError(poolName);
2759
+ }
2760
+ return filteredNodeUrls;
2761
+ }
2762
+ function getSystemClient(directoryNodeUrlPool, directoryChainRid, blockedNodeUrlSubstrings, nodeUrlFilter) {
2736
2763
  return __awaiter(this, void 0, void 0, function* () {
2737
2764
  return yield (0, blockchainClient_1.createClient)({
2738
2765
  directoryNodeUrlPool,
2739
2766
  blockchainRid: directoryChainRid,
2767
+ blockedNodeUrlSubstrings,
2768
+ nodeUrlFilter,
2740
2769
  });
2741
2770
  });
2742
2771
  }
@@ -2865,16 +2894,16 @@ function requireUtils$1 () {
2865
2894
  }
2866
2895
  function getAnchoringClientAndSystemChainRid(client) {
2867
2896
  return __awaiter(this, void 0, void 0, function* () {
2868
- const directoryClient = yield getSystemClient((0, exports.getUrlsFromEndpoints)(client.config.endpointPool), client.config.directoryChainRid);
2897
+ const directoryClient = yield getSystemClient((0, exports.getUrlsFromEndpoints)(client.config.endpointPool), client.config.directoryChainRid, client.config.blockedNodeUrlSubstrings, client.config.nodeUrlFilter);
2869
2898
  const anchoringClient = yield (0, IccfProofTxMaterialBuilder_1.getAnchoringClient)(directoryClient, client.config.blockchainRid);
2870
2899
  const systemAnchoringChainRidBuffer = yield getSystemAnchoringChain(directoryClient);
2871
2900
  const systemAnchoringChainBridString = systemAnchoringChainRidBuffer.toString("hex");
2872
2901
  return { anchoringClient, systemAnchoringChainBridString };
2873
2902
  });
2874
2903
  }
2875
- function getSystemAnchoringTransaction(dappClientEndpointPool, anchoredTxRid, anchoringClient, systemAnchoringChainRid, systemAnchoringStatusPolling, merkleHashVersion) {
2904
+ function getSystemAnchoringTransaction(dappClientEndpointPool, anchoredTxRid, anchoringClient, systemAnchoringChainRid, systemAnchoringStatusPolling, merkleHashVersion, blockedNodeUrlSubstrings, nodeUrlFilter) {
2876
2905
  return __awaiter(this, void 0, void 0, function* () {
2877
- const systemAnchoringChainClient = yield getSystemClient((0, exports.getUrlsFromEndpoints)(dappClientEndpointPool), systemAnchoringChainRid);
2906
+ const systemAnchoringChainClient = yield getSystemClient((0, exports.getUrlsFromEndpoints)(dappClientEndpointPool), systemAnchoringChainRid, blockedNodeUrlSubstrings, nodeUrlFilter);
2878
2907
  const clusterAnchoringProof = yield anchoringClient.getConfirmationProof(anchoredTxRid);
2879
2908
  const clusterBlockRid = (0, utils_1.calculateBlockRID)(clusterAnchoringProof, merkleHashVersion);
2880
2909
  const systemAnchoringTransactionConfirmation = yield (0, utils_1.awaitGetAnchoringTransactionForBlockRid)(systemAnchoringChainClient, (0, formatter_1.toBuffer)(anchoringClient.config.blockchainRid), clusterBlockRid, systemAnchoringStatusPolling);
@@ -3250,6 +3279,8 @@ function requireIccfProofTxMaterialBuilder () {
3250
3279
  blockchainRid: (0, formatter_1.ensureString)(sourceBlockchainRid),
3251
3280
  merkleHashVersion: merkleHashVersion,
3252
3281
  useStickyNode: true,
3282
+ blockedNodeUrlSubstrings: directoryClient.config.blockedNodeUrlSubstrings,
3283
+ nodeUrlFilter: directoryClient.config.nodeUrlFilter,
3253
3284
  });
3254
3285
  }
3255
3286
  else {
@@ -3258,6 +3289,8 @@ function requireIccfProofTxMaterialBuilder () {
3258
3289
  blockchainRid: (0, formatter_1.ensureString)(sourceBlockchainRid),
3259
3290
  merkleHashVersion: merkleHashVersion,
3260
3291
  useStickyNode: true,
3292
+ blockedNodeUrlSubstrings: directoryClient.config.blockedNodeUrlSubstrings,
3293
+ nodeUrlFilter: directoryClient.config.nodeUrlFilter,
3261
3294
  });
3262
3295
  }
3263
3296
  const txProof = yield clientConfiguredToSource.getConfirmationProof(txToProveRid);
@@ -4036,7 +4069,7 @@ function requireBlockchainClient () {
4036
4069
  }
4037
4070
  result.status = enums_1.AnchoringStatus.ClusterAnchored;
4038
4071
  result.clusterAnchoredTx = anchoringTransactionValidation.data;
4039
- const systemAnchoredTransaction = yield (0, utils_1.getSystemAnchoringTransaction)(config.endpointPool, anchoringTransactionValidation.data.txRid, anchoringClient, systemAnchoringChainRid, config.systemAnchoringStatusPolling, config.merkleHashVersion);
4072
+ const systemAnchoredTransaction = yield (0, utils_1.getSystemAnchoringTransaction)(config.endpointPool, anchoringTransactionValidation.data.txRid, anchoringClient, systemAnchoringChainRid, config.systemAnchoringStatusPolling, config.merkleHashVersion, config.blockedNodeUrlSubstrings, config.nodeUrlFilter);
4040
4073
  if (!systemAnchoredTransaction) {
4041
4074
  return result;
4042
4075
  }
@@ -4266,7 +4299,7 @@ function requireBlockchainClient () {
4266
4299
  callback === null || callback === void 0 ? void 0 : callback(error, null);
4267
4300
  throw error;
4268
4301
  }
4269
- const systemAnchoringTransactionTransaction = yield (0, utils_1.getSystemAnchoringTransaction)(config.endpointPool, anchoredTxRid, anchoringClient, systemAnchoringChainRid, config.systemAnchoringStatusPolling, config.merkleHashVersion);
4302
+ const systemAnchoringTransactionTransaction = yield (0, utils_1.getSystemAnchoringTransaction)(config.endpointPool, anchoredTxRid, anchoringClient, systemAnchoringChainRid, config.systemAnchoringStatusPolling, config.merkleHashVersion, config.blockedNodeUrlSubstrings, config.nodeUrlFilter);
4270
4303
  return systemAnchoringTransactionTransaction;
4271
4304
  });
4272
4305
  },
@@ -4339,6 +4372,8 @@ function requireBlockchainClient () {
4339
4372
  blockchainRid: client.config.blockchainRid,
4340
4373
  merkleHashVersion: client.config.merkleHashVersion,
4341
4374
  useStickyNode: true,
4375
+ blockedNodeUrlSubstrings: client.config.blockedNodeUrlSubstrings,
4376
+ nodeUrlFilter: client.config.nodeUrlFilter,
4342
4377
  });
4343
4378
  return stickyNodeClient;
4344
4379
  });