@settlemint/sdk-utils 2.3.2-prb7d863c7 → 2.3.2-prbe16a4a1

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
@@ -39,6 +39,7 @@
39
39
  - [ensureServer()](#ensureserver)
40
40
  - [executeCommand()](#executecommand)
41
41
  - [exists()](#exists)
42
+ - [extractBaseUrlBeforeSegment()](#extractbaseurlbeforesegment)
42
43
  - [extractJsonObject()](#extractjsonobject)
43
44
  - [fetchWithRetry()](#fetchwithretry)
44
45
  - [findMonoRepoPackages()](#findmonorepopackages)
@@ -91,6 +92,7 @@
91
92
  - [PersonalAccessTokenSchema](#personalaccesstokenschema)
92
93
  - [runsInBrowser](#runsinbrowser)
93
94
  - [runsOnServer](#runsonserver)
95
+ - [STANDALONE\_INSTANCE](#standalone_instance)
94
96
  - [UniqueNameSchema](#uniquenameschema)
95
97
  - [UrlOrPathSchema](#urlorpathschema)
96
98
  - [UrlPathSchema](#urlpathschema)
@@ -415,6 +417,38 @@ if (await exists('/path/to/file.txt')) {
415
417
 
416
418
  ***
417
419
 
420
+ #### extractBaseUrlBeforeSegment()
421
+
422
+ > **extractBaseUrlBeforeSegment**(`baseUrl`, `pathSegment`): `string`
423
+
424
+ Defined in: [sdk/utils/src/url.ts:15](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/url.ts#L15)
425
+
426
+ Extracts the base URL before a specific segment in a URL.
427
+
428
+ ##### Parameters
429
+
430
+ | Parameter | Type | Description |
431
+ | ------ | ------ | ------ |
432
+ | `baseUrl` | `string` | The base URL to extract the path from |
433
+ | `pathSegment` | `string` | The path segment to start from |
434
+
435
+ ##### Returns
436
+
437
+ `string`
438
+
439
+ The base URL before the specified segment
440
+
441
+ ##### Example
442
+
443
+ ```typescript
444
+ import { extractBaseUrlBeforeSegment } from "@settlemint/sdk-utils/url";
445
+
446
+ const baseUrl = extractBaseUrlBeforeSegment("https://example.com/api/v1/subgraphs/name/my-subgraph", "/subgraphs");
447
+ // Returns: "https://example.com/api/v1"
448
+ ```
449
+
450
+ ***
451
+
418
452
  #### extractJsonObject()
419
453
 
420
454
  > **extractJsonObject**\<`T`\>(`value`): `null` \| `T`
@@ -1174,7 +1208,7 @@ The fetch function
1174
1208
 
1175
1209
  > **retryWhenFailed**\<`T`\>(`fn`, `maxRetries`, `initialSleepTime`, `stopOnError?`): `Promise`\<`T`\>
1176
1210
 
1177
- Defined in: [sdk/utils/src/retry.ts:14](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/retry.ts#L14)
1211
+ Defined in: [sdk/utils/src/retry.ts:16](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/retry.ts#L16)
1178
1212
 
1179
1213
  Retry a function when it fails.
1180
1214
 
@@ -1663,7 +1697,7 @@ Options for configuring the spinner behavior
1663
1697
 
1664
1698
  > **DotEnv** = `z.infer`\<*typeof* [`DotEnvSchema`](#dotenvschema)\>
1665
1699
 
1666
- Defined in: [sdk/utils/src/validation/dot-env.schema.ts:101](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L101)
1700
+ Defined in: [sdk/utils/src/validation/dot-env.schema.ts:106](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L106)
1667
1701
 
1668
1702
  Type definition for the environment variables schema.
1669
1703
 
@@ -1673,7 +1707,7 @@ Type definition for the environment variables schema.
1673
1707
 
1674
1708
  > **DotEnvPartial** = `z.infer`\<*typeof* [`DotEnvSchemaPartial`](#dotenvschemapartial)\>
1675
1709
 
1676
- Defined in: [sdk/utils/src/validation/dot-env.schema.ts:112](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L112)
1710
+ Defined in: [sdk/utils/src/validation/dot-env.schema.ts:117](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L117)
1677
1711
 
1678
1712
  Type definition for the partial environment variables schema.
1679
1713
 
@@ -1724,9 +1758,9 @@ Application access tokens start with 'sm_aat_' prefix.
1724
1758
 
1725
1759
  #### DotEnvSchema
1726
1760
 
1727
- > `const` **DotEnvSchema**: `ZodObject`\<\{ `SETTLEMINT_ACCESS_TOKEN`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_ACCESSIBLE_PRIVATE_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_APPLICATION`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NETWORK`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT_UI_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_CUSTOM_DEPLOYMENT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_CUSTOM_DEPLOYMENT_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_ADMIN_SECRET`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_DATABASE_URL`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HD_PRIVATE_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HD_PRIVATE_KEY_FORWARDER_ADDRESS`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_INSTANCE`: `ZodDefault`\<`ZodString`\>; `SETTLEMINT_IPFS`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_API_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_GATEWAY_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_PINNING_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_LOG_LEVEL`: `ZodDefault`\<`ZodEnum`\<\{ `debug`: `"debug"`; `error`: `"error"`; `info`: `"info"`; `none`: `"none"`; `warn`: `"warn"`; \}\>\>; `SETTLEMINT_MINIO`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_ACCESS_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_SECRET_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_NEW_PROJECT_NAME`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_REST_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_WS_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH_DEFAULT_SUBGRAPH`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH_SUBGRAPHS_ENDPOINTS`: `ZodPipe`\<`ZodTransform`\<`null` \| `never`[], `unknown`\>, `ZodOptional`\<`ZodArray`\<`ZodString`\>\>\>; `SETTLEMINT_WORKSPACE`: `ZodOptional`\<`ZodString`\>; \}, `$strip`\>
1761
+ > `const` **DotEnvSchema**: `ZodObject`\<\{ `SETTLEMINT_ACCESS_TOKEN`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_ACCESSIBLE_PRIVATE_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_APPLICATION`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NETWORK`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_BLOCKSCOUT_UI_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_CUSTOM_DEPLOYMENT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_CUSTOM_DEPLOYMENT_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_ADMIN_SECRET`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_DATABASE_URL`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HASURA_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HD_PRIVATE_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_HD_PRIVATE_KEY_FORWARDER_ADDRESS`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_INSTANCE`: `ZodDefault`\<`ZodUnion`\<readonly \[`ZodString`, `ZodLiteral`\<`"standalone"`\>\]\>\>; `SETTLEMINT_IPFS`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_API_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_GATEWAY_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_IPFS_PINNING_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_LOG_LEVEL`: `ZodDefault`\<`ZodEnum`\<\{ `debug`: `"debug"`; `error`: `"error"`; `info`: `"info"`; `none`: `"none"`; `warn`: `"warn"`; \}\>\>; `SETTLEMINT_MINIO`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_ACCESS_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_MINIO_SECRET_KEY`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_NEW_PROJECT_NAME`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_REST_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_PORTAL_WS_ENDPOINT`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH_DEFAULT_SUBGRAPH`: `ZodOptional`\<`ZodString`\>; `SETTLEMINT_THEGRAPH_SUBGRAPHS_ENDPOINTS`: `ZodPipe`\<`ZodTransform`\<`null` \| `never`[], `unknown`\>, `ZodOptional`\<`ZodArray`\<`ZodString`\>\>\>; `SETTLEMINT_WORKSPACE`: `ZodOptional`\<`ZodString`\>; \}, `$strip`\>
1728
1762
 
1729
- Defined in: [sdk/utils/src/validation/dot-env.schema.ts:12](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L12)
1763
+ Defined in: [sdk/utils/src/validation/dot-env.schema.ts:17](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L17)
1730
1764
 
1731
1765
  Schema for validating environment variables used by the SettleMint SDK.
1732
1766
  Defines validation rules and types for configuration values like URLs,
@@ -1736,9 +1770,9 @@ access tokens, workspace names, and service endpoints.
1736
1770
 
1737
1771
  #### DotEnvSchemaPartial
1738
1772
 
1739
- > `const` **DotEnvSchemaPartial**: `ZodObject`\<\{ `SETTLEMINT_ACCESS_TOKEN`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_ACCESSIBLE_PRIVATE_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_APPLICATION`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NETWORK`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT_UI_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_CUSTOM_DEPLOYMENT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_CUSTOM_DEPLOYMENT_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_ADMIN_SECRET`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_DATABASE_URL`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HD_PRIVATE_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HD_PRIVATE_KEY_FORWARDER_ADDRESS`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_INSTANCE`: `ZodOptional`\<`ZodDefault`\<`ZodString`\>\>; `SETTLEMINT_IPFS`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_API_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_GATEWAY_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_PINNING_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_LOG_LEVEL`: `ZodOptional`\<`ZodDefault`\<`ZodEnum`\<\{ `debug`: `"debug"`; `error`: `"error"`; `info`: `"info"`; `none`: `"none"`; `warn`: `"warn"`; \}\>\>\>; `SETTLEMINT_MINIO`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_ACCESS_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_SECRET_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_NEW_PROJECT_NAME`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_REST_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_WS_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH_DEFAULT_SUBGRAPH`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH_SUBGRAPHS_ENDPOINTS`: `ZodOptional`\<`ZodPipe`\<`ZodTransform`\<`null` \| `never`[], `unknown`\>, `ZodOptional`\<`ZodArray`\<`ZodString`\>\>\>\>; `SETTLEMINT_WORKSPACE`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; \}, `$strip`\>
1773
+ > `const` **DotEnvSchemaPartial**: `ZodObject`\<\{ `SETTLEMINT_ACCESS_TOKEN`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_ACCESSIBLE_PRIVATE_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_APPLICATION`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NETWORK`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NETWORK_CHAIN_ID`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKCHAIN_NODE_OR_LOAD_BALANCER_JSON_RPC_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_BLOCKSCOUT_UI_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_CUSTOM_DEPLOYMENT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_CUSTOM_DEPLOYMENT_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_ADMIN_SECRET`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_DATABASE_URL`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HASURA_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HD_PRIVATE_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_HD_PRIVATE_KEY_FORWARDER_ADDRESS`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_INSTANCE`: `ZodOptional`\<`ZodDefault`\<`ZodUnion`\<readonly \[`ZodString`, `ZodLiteral`\<`"standalone"`\>\]\>\>\>; `SETTLEMINT_IPFS`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_API_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_GATEWAY_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_IPFS_PINNING_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_LOG_LEVEL`: `ZodOptional`\<`ZodDefault`\<`ZodEnum`\<\{ `debug`: `"debug"`; `error`: `"error"`; `info`: `"info"`; `none`: `"none"`; `warn`: `"warn"`; \}\>\>\>; `SETTLEMINT_MINIO`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_ACCESS_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_MINIO_SECRET_KEY`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_NEW_PROJECT_NAME`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_REST_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_PORTAL_WS_ENDPOINT`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH_DEFAULT_SUBGRAPH`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; `SETTLEMINT_THEGRAPH_SUBGRAPHS_ENDPOINTS`: `ZodOptional`\<`ZodPipe`\<`ZodTransform`\<`null` \| `never`[], `unknown`\>, `ZodOptional`\<`ZodArray`\<`ZodString`\>\>\>\>; `SETTLEMINT_WORKSPACE`: `ZodOptional`\<`ZodOptional`\<`ZodString`\>\>; \}, `$strip`\>
1740
1774
 
1741
- Defined in: [sdk/utils/src/validation/dot-env.schema.ts:107](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L107)
1775
+ Defined in: [sdk/utils/src/validation/dot-env.schema.ts:112](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L112)
1742
1776
 
1743
1777
  Partial version of the environment variables schema where all fields are optional.
1744
1778
  Useful for validating incomplete configurations during development or build time.
@@ -1800,6 +1834,16 @@ Boolean indicating if code is currently running in a server environment
1800
1834
 
1801
1835
  ***
1802
1836
 
1837
+ #### STANDALONE\_INSTANCE
1838
+
1839
+ > `const` **STANDALONE\_INSTANCE**: `"standalone"` = `"standalone"`
1840
+
1841
+ Defined in: [sdk/utils/src/validation/dot-env.schema.ts:10](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/utils/src/validation/dot-env.schema.ts#L10)
1842
+
1843
+ Use this value to indicate that the resources are not part of the SettleMint platform.
1844
+
1845
+ ***
1846
+
1803
1847
  #### UniqueNameSchema
1804
1848
 
1805
1849
  > `const` **UniqueNameSchema**: `ZodString`
package/dist/http.cjs CHANGED
@@ -26,25 +26,91 @@ __export(http_exports, {
26
26
  });
27
27
  module.exports = __toCommonJS(http_exports);
28
28
 
29
+ // src/logging/mask-tokens.ts
30
+ var maskTokens = (output) => {
31
+ return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, "***");
32
+ };
33
+
34
+ // src/logging/logger.ts
35
+ function createLogger(options = {}) {
36
+ const { level = "warn", prefix = "" } = options;
37
+ const logLevels = {
38
+ debug: 0,
39
+ info: 1,
40
+ warn: 2,
41
+ error: 3,
42
+ none: 4
43
+ };
44
+ const currentLevelValue = logLevels[level];
45
+ const formatArgs = (args) => {
46
+ if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
47
+ return "";
48
+ }
49
+ const formatted = args.map((arg) => {
50
+ if (arg instanceof Error) {
51
+ return `
52
+ ${arg.stack || arg.message}`;
53
+ }
54
+ if (typeof arg === "object" && arg !== null) {
55
+ return `
56
+ ${JSON.stringify(arg, null, 2)}`;
57
+ }
58
+ return ` ${String(arg)}`;
59
+ }).join("");
60
+ return `, args:${formatted}`;
61
+ };
62
+ const shouldLog = (level2) => {
63
+ return logLevels[level2] >= currentLevelValue;
64
+ };
65
+ return {
66
+ debug: (message, ...args) => {
67
+ if (shouldLog("debug")) {
68
+ console.debug(`\x1B[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
69
+ }
70
+ },
71
+ info: (message, ...args) => {
72
+ if (shouldLog("info")) {
73
+ console.info(`\x1B[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
74
+ }
75
+ },
76
+ warn: (message, ...args) => {
77
+ if (shouldLog("warn")) {
78
+ console.warn(`\x1B[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
79
+ }
80
+ },
81
+ error: (message, ...args) => {
82
+ if (shouldLog("error")) {
83
+ console.error(`\x1B[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
84
+ }
85
+ }
86
+ };
87
+ }
88
+ var logger = createLogger();
89
+
29
90
  // src/retry.ts
30
91
  async function retryWhenFailed(fn, maxRetries = 5, initialSleepTime = 1e3, stopOnError) {
31
- let attempt = 0;
32
- while (attempt < maxRetries) {
92
+ let retries = 0;
93
+ const maxAttempts = maxRetries + 1;
94
+ while (retries < maxAttempts) {
33
95
  try {
34
96
  return await fn();
35
97
  } catch (e) {
98
+ const error = e;
36
99
  if (typeof stopOnError === "function") {
37
- const error = e;
38
100
  if (stopOnError(error)) {
39
101
  throw error;
40
102
  }
41
103
  }
42
- attempt += 1;
43
- if (attempt >= maxRetries) {
104
+ if (retries >= maxRetries) {
44
105
  throw e;
45
106
  }
46
- const jitter = Math.random();
47
- const delay = 2 ** attempt * initialSleepTime * jitter;
107
+ const baseDelay = 2 ** retries * initialSleepTime;
108
+ const jitterAmount = initialSleepTime * (Math.random() / 10);
109
+ const delay = baseDelay + jitterAmount;
110
+ retries += 1;
111
+ logger.warn(
112
+ `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`
113
+ );
48
114
  await new Promise((resolve) => setTimeout(resolve, delay));
49
115
  }
50
116
  }
package/dist/http.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/http.ts","../src/retry.ts","../src/http/fetch-with-retry.ts","../src/http/graphql-fetch-with-retry.ts","../src/http/headers.ts"],"sourcesContent":["export { fetchWithRetry } from \"./http/fetch-with-retry.js\";\nexport { graphqlFetchWithRetry } from \"./http/graphql-fetch-with-retry.js\";\nexport { appendHeaders } from \"./http/headers.js\";\n","/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","import { retryWhenFailed } from \"../retry.js\";\n\n/**\n * Retry an HTTP request with exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n *\n * @param input - The URL or Request object to fetch\n * @param init - The fetch init options\n * @param maxRetries - Maximum number of retry attempts\n * @param initialSleepTime - Initial sleep time between retries in ms\n * @returns The fetch Response\n * @throws Error if all retries fail\n * @example\n * import { fetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const response = await fetchWithRetry(\"https://api.example.com/data\");\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Response> {\n return retryWhenFailed(\n async () => {\n const response = await fetch(input, init);\n if (response.ok) {\n return response;\n }\n // Only retry on 5xx server errors, 429 rate limit, timeout, and network errors\n if (response.status < 500 && response.status !== 429 && response.status !== 408 && response.status !== 0) {\n return response;\n }\n throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","import { retryWhenFailed } from \"../retry.js\";\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\n\n/**\n * Executes a GraphQL request with automatic retries using exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n * Will also retry if the GraphQL response contains errors.\n *\n * @param input - The URL or Request object for the GraphQL endpoint\n * @param init - Optional fetch configuration options\n * @param maxRetries - Maximum retry attempts before failing (default: 5)\n * @param initialSleepTime - Initial delay between retries in milliseconds (default: 3000)\n * @returns The parsed GraphQL response data\n * @throws Error if all retries fail or if GraphQL response contains errors\n * @example\n * import { graphqlFetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const data = await graphqlFetchWithRetry<{ user: { id: string } }>(\n * \"https://api.example.com/graphql\",\n * {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * query: `query GetUser($id: ID!) {\n * user(id: $id) {\n * id\n * }\n * }`,\n * variables: { id: \"123\" }\n * })\n * }\n * );\n */\nexport async function graphqlFetchWithRetry<Data>(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Data> {\n return retryWhenFailed<Data>(\n async () => {\n const response = await fetchWithRetry(input, init);\n const json: { errors?: { message: string }[]; data: Data } = await response.json();\n if (json.errors) {\n throw new Error(`GraphQL errors in response: ${json.errors.map((error) => error.message).join(\", \")}`);\n }\n return json.data;\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","type MaybeLazy<T> = T | (() => T);\n\nexport function appendHeaders(\n headers: MaybeLazy<HeadersInit> | undefined,\n additionalHeaders: Record<string, string | undefined>,\n) {\n const defaultHeaders = typeof headers === \"function\" ? headers() : headers;\n const filteredAdditionalHeaders = Object.entries(additionalHeaders).filter(([_, value]) => value !== undefined) as [\n string,\n string,\n ][];\n if (Array.isArray(defaultHeaders)) {\n return [...defaultHeaders, ...filteredAdditionalHeaders];\n }\n if (defaultHeaders instanceof Headers) {\n return new Headers([...defaultHeaders, ...filteredAdditionalHeaders]);\n }\n return {\n ...defaultHeaders,\n ...Object.fromEntries(filteredAdditionalHeaders),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC1BA,eAAsB,eACpB,OACA,MACA,aAAa,GACb,mBAAmB,KACA;AACnB,SAAO;AAAA,IACL,YAAY;AACV,YAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AACxC,UAAI,SAAS,IAAI;AACf,eAAO;AAAA,MACT;AAEA,UAAI,SAAS,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW,GAAG;AACxG,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACLA,eAAsB,sBACpB,OACA,MACA,aAAa,GACb,mBAAmB,KACJ;AACf,SAAO;AAAA,IACL,YAAY;AACV,YAAM,WAAW,MAAM,eAAe,OAAO,IAAI;AACjD,YAAM,OAAuD,MAAM,SAAS,KAAK;AACjF,UAAI,KAAK,QAAQ;AACf,cAAM,IAAI,MAAM,+BAA+B,KAAK,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,MACvG;AACA,aAAO,KAAK;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjDO,SAAS,cACd,SACA,mBACA;AACA,QAAM,iBAAiB,OAAO,YAAY,aAAa,QAAQ,IAAI;AACnE,QAAM,4BAA4B,OAAO,QAAQ,iBAAiB,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM,UAAU,MAAS;AAI9G,MAAI,MAAM,QAAQ,cAAc,GAAG;AACjC,WAAO,CAAC,GAAG,gBAAgB,GAAG,yBAAyB;AAAA,EACzD;AACA,MAAI,0BAA0B,SAAS;AACrC,WAAO,IAAI,QAAQ,CAAC,GAAG,gBAAgB,GAAG,yBAAyB,CAAC;AAAA,EACtE;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG,OAAO,YAAY,yBAAyB;AAAA,EACjD;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/http.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/http/fetch-with-retry.ts","../src/http/graphql-fetch-with-retry.ts","../src/http/headers.ts"],"sourcesContent":["export { fetchWithRetry } from \"./http/fetch-with-retry.js\";\nexport { graphqlFetchWithRetry } from \"./http/graphql-fetch-with-retry.js\";\nexport { appendHeaders } from \"./http/headers.js\";\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","import { logger } from \"./logging/logger.js\";\n\n/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let retries = 0;\n const maxAttempts = maxRetries + 1;\n\n while (retries < maxAttempts) {\n try {\n return await fn();\n } catch (e) {\n const error = e as Error;\n if (typeof stopOnError === \"function\") {\n if (stopOnError(error)) {\n throw error;\n }\n }\n if (retries >= maxRetries) {\n throw e;\n }\n // Exponential backoff with jitter to prevent thundering herd\n // Jitter: Random value between 0-10% of initialSleepTime\n const baseDelay = 2 ** retries * initialSleepTime;\n const jitterAmount = initialSleepTime * (Math.random() / 10);\n const delay = baseDelay + jitterAmount;\n retries += 1;\n logger.warn(\n `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","import { retryWhenFailed } from \"../retry.js\";\n\n/**\n * Retry an HTTP request with exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n *\n * @param input - The URL or Request object to fetch\n * @param init - The fetch init options\n * @param maxRetries - Maximum number of retry attempts\n * @param initialSleepTime - Initial sleep time between retries in ms\n * @returns The fetch Response\n * @throws Error if all retries fail\n * @example\n * import { fetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const response = await fetchWithRetry(\"https://api.example.com/data\");\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Response> {\n return retryWhenFailed(\n async () => {\n const response = await fetch(input, init);\n if (response.ok) {\n return response;\n }\n // Only retry on 5xx server errors, 429 rate limit, timeout, and network errors\n if (response.status < 500 && response.status !== 429 && response.status !== 408 && response.status !== 0) {\n return response;\n }\n throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","import { retryWhenFailed } from \"../retry.js\";\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\n\n/**\n * Executes a GraphQL request with automatic retries using exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n * Will also retry if the GraphQL response contains errors.\n *\n * @param input - The URL or Request object for the GraphQL endpoint\n * @param init - Optional fetch configuration options\n * @param maxRetries - Maximum retry attempts before failing (default: 5)\n * @param initialSleepTime - Initial delay between retries in milliseconds (default: 3000)\n * @returns The parsed GraphQL response data\n * @throws Error if all retries fail or if GraphQL response contains errors\n * @example\n * import { graphqlFetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const data = await graphqlFetchWithRetry<{ user: { id: string } }>(\n * \"https://api.example.com/graphql\",\n * {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * query: `query GetUser($id: ID!) {\n * user(id: $id) {\n * id\n * }\n * }`,\n * variables: { id: \"123\" }\n * })\n * }\n * );\n */\nexport async function graphqlFetchWithRetry<Data>(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Data> {\n return retryWhenFailed<Data>(\n async () => {\n const response = await fetchWithRetry(input, init);\n const json: { errors?: { message: string }[]; data: Data } = await response.json();\n if (json.errors) {\n throw new Error(`GraphQL errors in response: ${json.errors.map((error) => error.message).join(\", \")}`);\n }\n return json.data;\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","type MaybeLazy<T> = T | (() => T);\n\nexport function appendHeaders(\n headers: MaybeLazy<HeadersInit> | undefined,\n additionalHeaders: Record<string, string | undefined>,\n) {\n const defaultHeaders = typeof headers === \"function\" ? headers() : headers;\n const filteredAdditionalHeaders = Object.entries(additionalHeaders).filter(([_, value]) => value !== undefined) as [\n string,\n string,\n ][];\n if (Array.isArray(defaultHeaders)) {\n return [...defaultHeaders, ...filteredAdditionalHeaders];\n }\n if (defaultHeaders instanceof Headers) {\n return new Headers([...defaultHeaders, ...filteredAdditionalHeaders]);\n }\n return {\n ...defaultHeaders,\n ...Object.fromEntries(filteredAdditionalHeaders),\n };\n}\n"],"mappings":"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","names":["level"]}
package/dist/http.mjs CHANGED
@@ -1,22 +1,88 @@
1
+ // src/logging/mask-tokens.ts
2
+ var maskTokens = (output) => {
3
+ return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, "***");
4
+ };
5
+
6
+ // src/logging/logger.ts
7
+ function createLogger(options = {}) {
8
+ const { level = "warn", prefix = "" } = options;
9
+ const logLevels = {
10
+ debug: 0,
11
+ info: 1,
12
+ warn: 2,
13
+ error: 3,
14
+ none: 4
15
+ };
16
+ const currentLevelValue = logLevels[level];
17
+ const formatArgs = (args) => {
18
+ if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
19
+ return "";
20
+ }
21
+ const formatted = args.map((arg) => {
22
+ if (arg instanceof Error) {
23
+ return `
24
+ ${arg.stack || arg.message}`;
25
+ }
26
+ if (typeof arg === "object" && arg !== null) {
27
+ return `
28
+ ${JSON.stringify(arg, null, 2)}`;
29
+ }
30
+ return ` ${String(arg)}`;
31
+ }).join("");
32
+ return `, args:${formatted}`;
33
+ };
34
+ const shouldLog = (level2) => {
35
+ return logLevels[level2] >= currentLevelValue;
36
+ };
37
+ return {
38
+ debug: (message, ...args) => {
39
+ if (shouldLog("debug")) {
40
+ console.debug(`\x1B[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
41
+ }
42
+ },
43
+ info: (message, ...args) => {
44
+ if (shouldLog("info")) {
45
+ console.info(`\x1B[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
46
+ }
47
+ },
48
+ warn: (message, ...args) => {
49
+ if (shouldLog("warn")) {
50
+ console.warn(`\x1B[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
51
+ }
52
+ },
53
+ error: (message, ...args) => {
54
+ if (shouldLog("error")) {
55
+ console.error(`\x1B[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
56
+ }
57
+ }
58
+ };
59
+ }
60
+ var logger = createLogger();
61
+
1
62
  // src/retry.ts
2
63
  async function retryWhenFailed(fn, maxRetries = 5, initialSleepTime = 1e3, stopOnError) {
3
- let attempt = 0;
4
- while (attempt < maxRetries) {
64
+ let retries = 0;
65
+ const maxAttempts = maxRetries + 1;
66
+ while (retries < maxAttempts) {
5
67
  try {
6
68
  return await fn();
7
69
  } catch (e) {
70
+ const error = e;
8
71
  if (typeof stopOnError === "function") {
9
- const error = e;
10
72
  if (stopOnError(error)) {
11
73
  throw error;
12
74
  }
13
75
  }
14
- attempt += 1;
15
- if (attempt >= maxRetries) {
76
+ if (retries >= maxRetries) {
16
77
  throw e;
17
78
  }
18
- const jitter = Math.random();
19
- const delay = 2 ** attempt * initialSleepTime * jitter;
79
+ const baseDelay = 2 ** retries * initialSleepTime;
80
+ const jitterAmount = initialSleepTime * (Math.random() / 10);
81
+ const delay = baseDelay + jitterAmount;
82
+ retries += 1;
83
+ logger.warn(
84
+ `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`
85
+ );
20
86
  await new Promise((resolve) => setTimeout(resolve, delay));
21
87
  }
22
88
  }
package/dist/http.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/retry.ts","../src/http/fetch-with-retry.ts","../src/http/graphql-fetch-with-retry.ts","../src/http/headers.ts"],"sourcesContent":["/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","import { retryWhenFailed } from \"../retry.js\";\n\n/**\n * Retry an HTTP request with exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n *\n * @param input - The URL or Request object to fetch\n * @param init - The fetch init options\n * @param maxRetries - Maximum number of retry attempts\n * @param initialSleepTime - Initial sleep time between retries in ms\n * @returns The fetch Response\n * @throws Error if all retries fail\n * @example\n * import { fetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const response = await fetchWithRetry(\"https://api.example.com/data\");\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Response> {\n return retryWhenFailed(\n async () => {\n const response = await fetch(input, init);\n if (response.ok) {\n return response;\n }\n // Only retry on 5xx server errors, 429 rate limit, timeout, and network errors\n if (response.status < 500 && response.status !== 429 && response.status !== 408 && response.status !== 0) {\n return response;\n }\n throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","import { retryWhenFailed } from \"../retry.js\";\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\n\n/**\n * Executes a GraphQL request with automatic retries using exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n * Will also retry if the GraphQL response contains errors.\n *\n * @param input - The URL or Request object for the GraphQL endpoint\n * @param init - Optional fetch configuration options\n * @param maxRetries - Maximum retry attempts before failing (default: 5)\n * @param initialSleepTime - Initial delay between retries in milliseconds (default: 3000)\n * @returns The parsed GraphQL response data\n * @throws Error if all retries fail or if GraphQL response contains errors\n * @example\n * import { graphqlFetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const data = await graphqlFetchWithRetry<{ user: { id: string } }>(\n * \"https://api.example.com/graphql\",\n * {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * query: `query GetUser($id: ID!) {\n * user(id: $id) {\n * id\n * }\n * }`,\n * variables: { id: \"123\" }\n * })\n * }\n * );\n */\nexport async function graphqlFetchWithRetry<Data>(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Data> {\n return retryWhenFailed<Data>(\n async () => {\n const response = await fetchWithRetry(input, init);\n const json: { errors?: { message: string }[]; data: Data } = await response.json();\n if (json.errors) {\n throw new Error(`GraphQL errors in response: ${json.errors.map((error) => error.message).join(\", \")}`);\n }\n return json.data;\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","type MaybeLazy<T> = T | (() => T);\n\nexport function appendHeaders(\n headers: MaybeLazy<HeadersInit> | undefined,\n additionalHeaders: Record<string, string | undefined>,\n) {\n const defaultHeaders = typeof headers === \"function\" ? headers() : headers;\n const filteredAdditionalHeaders = Object.entries(additionalHeaders).filter(([_, value]) => value !== undefined) as [\n string,\n string,\n ][];\n if (Array.isArray(defaultHeaders)) {\n return [...defaultHeaders, ...filteredAdditionalHeaders];\n }\n if (defaultHeaders instanceof Headers) {\n return new Headers([...defaultHeaders, ...filteredAdditionalHeaders]);\n }\n return {\n ...defaultHeaders,\n ...Object.fromEntries(filteredAdditionalHeaders),\n };\n}\n"],"mappings":";AAaA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC1BA,eAAsB,eACpB,OACA,MACA,aAAa,GACb,mBAAmB,KACA;AACnB,SAAO;AAAA,IACL,YAAY;AACV,YAAM,WAAW,MAAM,MAAM,OAAO,IAAI;AACxC,UAAI,SAAS,IAAI;AACf,eAAO;AAAA,MACT;AAEA,UAAI,SAAS,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW,OAAO,SAAS,WAAW,GAAG;AACxG,eAAO;AAAA,MACT;AACA,YAAM,IAAI,MAAM,uBAAuB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IACjF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACLA,eAAsB,sBACpB,OACA,MACA,aAAa,GACb,mBAAmB,KACJ;AACf,SAAO;AAAA,IACL,YAAY;AACV,YAAM,WAAW,MAAM,eAAe,OAAO,IAAI;AACjD,YAAM,OAAuD,MAAM,SAAS,KAAK;AACjF,UAAI,KAAK,QAAQ;AACf,cAAM,IAAI,MAAM,+BAA+B,KAAK,OAAO,IAAI,CAAC,UAAU,MAAM,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,MACvG;AACA,aAAO,KAAK;AAAA,IACd;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ACjDO,SAAS,cACd,SACA,mBACA;AACA,QAAM,iBAAiB,OAAO,YAAY,aAAa,QAAQ,IAAI;AACnE,QAAM,4BAA4B,OAAO,QAAQ,iBAAiB,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,MAAM,UAAU,MAAS;AAI9G,MAAI,MAAM,QAAQ,cAAc,GAAG;AACjC,WAAO,CAAC,GAAG,gBAAgB,GAAG,yBAAyB;AAAA,EACzD;AACA,MAAI,0BAA0B,SAAS;AACrC,WAAO,IAAI,QAAQ,CAAC,GAAG,gBAAgB,GAAG,yBAAyB,CAAC;AAAA,EACtE;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG,OAAO,YAAY,yBAAyB;AAAA,EACjD;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/http/fetch-with-retry.ts","../src/http/graphql-fetch-with-retry.ts","../src/http/headers.ts"],"sourcesContent":["/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","import { logger } from \"./logging/logger.js\";\n\n/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let retries = 0;\n const maxAttempts = maxRetries + 1;\n\n while (retries < maxAttempts) {\n try {\n return await fn();\n } catch (e) {\n const error = e as Error;\n if (typeof stopOnError === \"function\") {\n if (stopOnError(error)) {\n throw error;\n }\n }\n if (retries >= maxRetries) {\n throw e;\n }\n // Exponential backoff with jitter to prevent thundering herd\n // Jitter: Random value between 0-10% of initialSleepTime\n const baseDelay = 2 ** retries * initialSleepTime;\n const jitterAmount = initialSleepTime * (Math.random() / 10);\n const delay = baseDelay + jitterAmount;\n retries += 1;\n logger.warn(\n `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","import { retryWhenFailed } from \"../retry.js\";\n\n/**\n * Retry an HTTP request with exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n *\n * @param input - The URL or Request object to fetch\n * @param init - The fetch init options\n * @param maxRetries - Maximum number of retry attempts\n * @param initialSleepTime - Initial sleep time between retries in ms\n * @returns The fetch Response\n * @throws Error if all retries fail\n * @example\n * import { fetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const response = await fetchWithRetry(\"https://api.example.com/data\");\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Response> {\n return retryWhenFailed(\n async () => {\n const response = await fetch(input, init);\n if (response.ok) {\n return response;\n }\n // Only retry on 5xx server errors, 429 rate limit, timeout, and network errors\n if (response.status < 500 && response.status !== 429 && response.status !== 408 && response.status !== 0) {\n return response;\n }\n throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","import { retryWhenFailed } from \"../retry.js\";\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\n\n/**\n * Executes a GraphQL request with automatic retries using exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n * Will also retry if the GraphQL response contains errors.\n *\n * @param input - The URL or Request object for the GraphQL endpoint\n * @param init - Optional fetch configuration options\n * @param maxRetries - Maximum retry attempts before failing (default: 5)\n * @param initialSleepTime - Initial delay between retries in milliseconds (default: 3000)\n * @returns The parsed GraphQL response data\n * @throws Error if all retries fail or if GraphQL response contains errors\n * @example\n * import { graphqlFetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const data = await graphqlFetchWithRetry<{ user: { id: string } }>(\n * \"https://api.example.com/graphql\",\n * {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * query: `query GetUser($id: ID!) {\n * user(id: $id) {\n * id\n * }\n * }`,\n * variables: { id: \"123\" }\n * })\n * }\n * );\n */\nexport async function graphqlFetchWithRetry<Data>(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Data> {\n return retryWhenFailed<Data>(\n async () => {\n const response = await fetchWithRetry(input, init);\n const json: { errors?: { message: string }[]; data: Data } = await response.json();\n if (json.errors) {\n throw new Error(`GraphQL errors in response: ${json.errors.map((error) => error.message).join(\", \")}`);\n }\n return json.data;\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","type MaybeLazy<T> = T | (() => T);\n\nexport function appendHeaders(\n headers: MaybeLazy<HeadersInit> | undefined,\n additionalHeaders: Record<string, string | undefined>,\n) {\n const defaultHeaders = typeof headers === \"function\" ? headers() : headers;\n const filteredAdditionalHeaders = Object.entries(additionalHeaders).filter(([_, value]) => value !== undefined) as [\n string,\n string,\n ][];\n if (Array.isArray(defaultHeaders)) {\n return [...defaultHeaders, ...filteredAdditionalHeaders];\n }\n if (defaultHeaders instanceof Headers) {\n return new Headers([...defaultHeaders, ...filteredAdditionalHeaders]);\n }\n return {\n ...defaultHeaders,\n ...Object.fromEntries(filteredAdditionalHeaders),\n };\n}\n"],"mappings":"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","names":["level"]}
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  camelCaseToWords: () => camelCaseToWords,
24
24
  capitalizeFirstLetter: () => capitalizeFirstLetter,
25
+ extractBaseUrlBeforeSegment: () => extractBaseUrlBeforeSegment,
25
26
  extractJsonObject: () => extractJsonObject,
26
27
  makeJsonStringifiable: () => makeJsonStringifiable,
27
28
  replaceUnderscoresAndHyphensWithSpaces: () => replaceUnderscoresAndHyphensWithSpaces,
@@ -66,25 +67,91 @@ function makeJsonStringifiable(value) {
66
67
  );
67
68
  }
68
69
 
70
+ // src/logging/mask-tokens.ts
71
+ var maskTokens = (output) => {
72
+ return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, "***");
73
+ };
74
+
75
+ // src/logging/logger.ts
76
+ function createLogger(options = {}) {
77
+ const { level = "warn", prefix = "" } = options;
78
+ const logLevels = {
79
+ debug: 0,
80
+ info: 1,
81
+ warn: 2,
82
+ error: 3,
83
+ none: 4
84
+ };
85
+ const currentLevelValue = logLevels[level];
86
+ const formatArgs = (args) => {
87
+ if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
88
+ return "";
89
+ }
90
+ const formatted = args.map((arg) => {
91
+ if (arg instanceof Error) {
92
+ return `
93
+ ${arg.stack || arg.message}`;
94
+ }
95
+ if (typeof arg === "object" && arg !== null) {
96
+ return `
97
+ ${JSON.stringify(arg, null, 2)}`;
98
+ }
99
+ return ` ${String(arg)}`;
100
+ }).join("");
101
+ return `, args:${formatted}`;
102
+ };
103
+ const shouldLog = (level2) => {
104
+ return logLevels[level2] >= currentLevelValue;
105
+ };
106
+ return {
107
+ debug: (message, ...args) => {
108
+ if (shouldLog("debug")) {
109
+ console.debug(`\x1B[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
110
+ }
111
+ },
112
+ info: (message, ...args) => {
113
+ if (shouldLog("info")) {
114
+ console.info(`\x1B[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
115
+ }
116
+ },
117
+ warn: (message, ...args) => {
118
+ if (shouldLog("warn")) {
119
+ console.warn(`\x1B[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
120
+ }
121
+ },
122
+ error: (message, ...args) => {
123
+ if (shouldLog("error")) {
124
+ console.error(`\x1B[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
125
+ }
126
+ }
127
+ };
128
+ }
129
+ var logger = createLogger();
130
+
69
131
  // src/retry.ts
70
132
  async function retryWhenFailed(fn, maxRetries = 5, initialSleepTime = 1e3, stopOnError) {
71
- let attempt = 0;
72
- while (attempt < maxRetries) {
133
+ let retries = 0;
134
+ const maxAttempts = maxRetries + 1;
135
+ while (retries < maxAttempts) {
73
136
  try {
74
137
  return await fn();
75
138
  } catch (e) {
139
+ const error = e;
76
140
  if (typeof stopOnError === "function") {
77
- const error = e;
78
141
  if (stopOnError(error)) {
79
142
  throw error;
80
143
  }
81
144
  }
82
- attempt += 1;
83
- if (attempt >= maxRetries) {
145
+ if (retries >= maxRetries) {
84
146
  throw e;
85
147
  }
86
- const jitter = Math.random();
87
- const delay = 2 ** attempt * initialSleepTime * jitter;
148
+ const baseDelay = 2 ** retries * initialSleepTime;
149
+ const jitterAmount = initialSleepTime * (Math.random() / 10);
150
+ const delay = baseDelay + jitterAmount;
151
+ retries += 1;
152
+ logger.warn(
153
+ `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`
154
+ );
88
155
  await new Promise((resolve) => setTimeout(resolve, delay));
89
156
  }
90
157
  }
@@ -110,10 +177,18 @@ function truncate(value, maxLength) {
110
177
  }
111
178
  return `${value.slice(0, maxLength)}...`;
112
179
  }
180
+
181
+ // src/url.ts
182
+ function extractBaseUrlBeforeSegment(baseUrl, pathSegment) {
183
+ const url = new URL(baseUrl);
184
+ const segmentIndex = url.pathname.indexOf(pathSegment);
185
+ return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);
186
+ }
113
187
  // Annotate the CommonJS export names for ESM import in node:
114
188
  0 && (module.exports = {
115
189
  camelCaseToWords,
116
190
  capitalizeFirstLetter,
191
+ extractBaseUrlBeforeSegment,
117
192
  extractJsonObject,
118
193
  makeJsonStringifiable,
119
194
  replaceUnderscoresAndHyphensWithSpaces,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["export * from \"./json.js\";\nexport * from \"./retry.js\";\nexport * from \"./string.js\";\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;AAgBO,SAAS,kBAAqB,OAAyB;AAC5D,MAAI,MAAM,SAAS,KAAM;AACvB,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACA,QAAM,SAAS,gBAAgB,KAAK,KAAK;AACzC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,SAAO,aAAgB,OAAO,CAAC,CAAC;AAClC;AAcO,SAAS,sBAAyB,OAAmB;AAC1D,MAAI,UAAU,UAAa,UAAU,MAAM;AACzC,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,KAAK;AAAA,MACH;AAAA,MACA,CAAC,GAAGA,WAAW,OAAOA,WAAU,WAAWA,OAAM,SAAS,IAAIA;AAAA;AAAA,IAChE;AAAA,EACF;AACF;;;ACrEA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;AAeO,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;","names":["value"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["export * from \"./json.js\";\nexport * from \"./retry.js\";\nexport * from \"./string.js\";\nexport * from \"./url.js\";\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","import { logger } from \"./logging/logger.js\";\n\n/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let retries = 0;\n const maxAttempts = maxRetries + 1;\n\n while (retries < maxAttempts) {\n try {\n return await fn();\n } catch (e) {\n const error = e as Error;\n if (typeof stopOnError === \"function\") {\n if (stopOnError(error)) {\n throw error;\n }\n }\n if (retries >= maxRetries) {\n throw e;\n }\n // Exponential backoff with jitter to prevent thundering herd\n // Jitter: Random value between 0-10% of initialSleepTime\n const baseDelay = 2 ** retries * initialSleepTime;\n const jitterAmount = initialSleepTime * (Math.random() / 10);\n const delay = baseDelay + jitterAmount;\n retries += 1;\n logger.warn(\n `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":"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","names":["value","level"]}
package/dist/index.d.cts CHANGED
@@ -119,4 +119,20 @@ declare function replaceUnderscoresAndHyphensWithSpaces(s: string): string;
119
119
  */
120
120
  declare function truncate(value: string, maxLength: number): string;
121
121
 
122
- export { camelCaseToWords, capitalizeFirstLetter, extractJsonObject, makeJsonStringifiable, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
122
+ /**
123
+ * Extracts the base URL before a specific segment in a URL.
124
+ *
125
+ * @param baseUrl - The base URL to extract the path from
126
+ * @param pathSegment - The path segment to start from
127
+ * @returns The base URL before the specified segment
128
+ * @example
129
+ * ```typescript
130
+ * import { extractBaseUrlBeforeSegment } from "@settlemint/sdk-utils/url";
131
+ *
132
+ * const baseUrl = extractBaseUrlBeforeSegment("https://example.com/api/v1/subgraphs/name/my-subgraph", "/subgraphs");
133
+ * // Returns: "https://example.com/api/v1"
134
+ * ```
135
+ */
136
+ declare function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string): string;
137
+
138
+ export { camelCaseToWords, capitalizeFirstLetter, extractBaseUrlBeforeSegment, extractJsonObject, makeJsonStringifiable, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
package/dist/index.d.ts CHANGED
@@ -119,4 +119,20 @@ declare function replaceUnderscoresAndHyphensWithSpaces(s: string): string;
119
119
  */
120
120
  declare function truncate(value: string, maxLength: number): string;
121
121
 
122
- export { camelCaseToWords, capitalizeFirstLetter, extractJsonObject, makeJsonStringifiable, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
122
+ /**
123
+ * Extracts the base URL before a specific segment in a URL.
124
+ *
125
+ * @param baseUrl - The base URL to extract the path from
126
+ * @param pathSegment - The path segment to start from
127
+ * @returns The base URL before the specified segment
128
+ * @example
129
+ * ```typescript
130
+ * import { extractBaseUrlBeforeSegment } from "@settlemint/sdk-utils/url";
131
+ *
132
+ * const baseUrl = extractBaseUrlBeforeSegment("https://example.com/api/v1/subgraphs/name/my-subgraph", "/subgraphs");
133
+ * // Returns: "https://example.com/api/v1"
134
+ * ```
135
+ */
136
+ declare function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string): string;
137
+
138
+ export { camelCaseToWords, capitalizeFirstLetter, extractBaseUrlBeforeSegment, extractJsonObject, makeJsonStringifiable, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
package/dist/index.mjs CHANGED
@@ -33,25 +33,91 @@ function makeJsonStringifiable(value) {
33
33
  );
34
34
  }
35
35
 
36
+ // src/logging/mask-tokens.ts
37
+ var maskTokens = (output) => {
38
+ return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, "***");
39
+ };
40
+
41
+ // src/logging/logger.ts
42
+ function createLogger(options = {}) {
43
+ const { level = "warn", prefix = "" } = options;
44
+ const logLevels = {
45
+ debug: 0,
46
+ info: 1,
47
+ warn: 2,
48
+ error: 3,
49
+ none: 4
50
+ };
51
+ const currentLevelValue = logLevels[level];
52
+ const formatArgs = (args) => {
53
+ if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
54
+ return "";
55
+ }
56
+ const formatted = args.map((arg) => {
57
+ if (arg instanceof Error) {
58
+ return `
59
+ ${arg.stack || arg.message}`;
60
+ }
61
+ if (typeof arg === "object" && arg !== null) {
62
+ return `
63
+ ${JSON.stringify(arg, null, 2)}`;
64
+ }
65
+ return ` ${String(arg)}`;
66
+ }).join("");
67
+ return `, args:${formatted}`;
68
+ };
69
+ const shouldLog = (level2) => {
70
+ return logLevels[level2] >= currentLevelValue;
71
+ };
72
+ return {
73
+ debug: (message, ...args) => {
74
+ if (shouldLog("debug")) {
75
+ console.debug(`\x1B[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
76
+ }
77
+ },
78
+ info: (message, ...args) => {
79
+ if (shouldLog("info")) {
80
+ console.info(`\x1B[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
81
+ }
82
+ },
83
+ warn: (message, ...args) => {
84
+ if (shouldLog("warn")) {
85
+ console.warn(`\x1B[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
86
+ }
87
+ },
88
+ error: (message, ...args) => {
89
+ if (shouldLog("error")) {
90
+ console.error(`\x1B[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\x1B[0m`);
91
+ }
92
+ }
93
+ };
94
+ }
95
+ var logger = createLogger();
96
+
36
97
  // src/retry.ts
37
98
  async function retryWhenFailed(fn, maxRetries = 5, initialSleepTime = 1e3, stopOnError) {
38
- let attempt = 0;
39
- while (attempt < maxRetries) {
99
+ let retries = 0;
100
+ const maxAttempts = maxRetries + 1;
101
+ while (retries < maxAttempts) {
40
102
  try {
41
103
  return await fn();
42
104
  } catch (e) {
105
+ const error = e;
43
106
  if (typeof stopOnError === "function") {
44
- const error = e;
45
107
  if (stopOnError(error)) {
46
108
  throw error;
47
109
  }
48
110
  }
49
- attempt += 1;
50
- if (attempt >= maxRetries) {
111
+ if (retries >= maxRetries) {
51
112
  throw e;
52
113
  }
53
- const jitter = Math.random();
54
- const delay = 2 ** attempt * initialSleepTime * jitter;
114
+ const baseDelay = 2 ** retries * initialSleepTime;
115
+ const jitterAmount = initialSleepTime * (Math.random() / 10);
116
+ const delay = baseDelay + jitterAmount;
117
+ retries += 1;
118
+ logger.warn(
119
+ `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`
120
+ );
55
121
  await new Promise((resolve) => setTimeout(resolve, delay));
56
122
  }
57
123
  }
@@ -77,9 +143,17 @@ function truncate(value, maxLength) {
77
143
  }
78
144
  return `${value.slice(0, maxLength)}...`;
79
145
  }
146
+
147
+ // src/url.ts
148
+ function extractBaseUrlBeforeSegment(baseUrl, pathSegment) {
149
+ const url = new URL(baseUrl);
150
+ const segmentIndex = url.pathname.indexOf(pathSegment);
151
+ return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);
152
+ }
80
153
  export {
81
154
  camelCaseToWords,
82
155
  capitalizeFirstLetter,
156
+ extractBaseUrlBeforeSegment,
83
157
  extractJsonObject,
84
158
  makeJsonStringifiable,
85
159
  replaceUnderscoresAndHyphensWithSpaces,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n"],"mappings":";AAsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;AAgBO,SAAS,kBAAqB,OAAyB;AAC5D,MAAI,MAAM,SAAS,KAAM;AACvB,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACA,QAAM,SAAS,gBAAgB,KAAK,KAAK;AACzC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,SAAO,aAAgB,OAAO,CAAC,CAAC;AAClC;AAcO,SAAS,sBAAyB,OAAmB;AAC1D,MAAI,UAAU,UAAa,UAAU,MAAM;AACzC,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,KAAK;AAAA,MACH;AAAA,MACA,CAAC,GAAGA,WAAW,OAAOA,WAAU,WAAWA,OAAM,SAAS,IAAIA;AAAA;AAAA,IAChE;AAAA,EACF;AACF;;;ACrEA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;AAeO,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;","names":["value"]}
1
+ {"version":3,"sources":["../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","import { logger } from \"./logging/logger.js\";\n\n/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let retries = 0;\n const maxAttempts = maxRetries + 1;\n\n while (retries < maxAttempts) {\n try {\n return await fn();\n } catch (e) {\n const error = e as Error;\n if (typeof stopOnError === \"function\") {\n if (stopOnError(error)) {\n throw error;\n }\n }\n if (retries >= maxRetries) {\n throw e;\n }\n // Exponential backoff with jitter to prevent thundering herd\n // Jitter: Random value between 0-10% of initialSleepTime\n const baseDelay = 2 ** retries * initialSleepTime;\n const jitterAmount = initialSleepTime * (Math.random() / 10);\n const delay = baseDelay + jitterAmount;\n retries += 1;\n logger.warn(\n `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":";AAsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;AAgBO,SAAS,kBAAqB,OAAyB;AAC5D,MAAI,MAAM,SAAS,KAAM;AACvB,UAAM,IAAI,MAAM,gBAAgB;AAAA,EAClC;AACA,QAAM,SAAS,gBAAgB,KAAK,KAAK;AACzC,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AACA,SAAO,aAAgB,OAAO,CAAC,CAAC;AAClC;AAcO,SAAS,sBAAyB,OAAmB;AAC1D,MAAI,UAAU,UAAa,UAAU,MAAM;AACzC,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,KAAK;AAAA,MACH;AAAA,MACA,CAAC,GAAGA,WAAW,OAAOA,WAAU,WAAWA,OAAM,SAAS,IAAIA;AAAA;AAAA,IAChE;AAAA,EACF;AACF;;;ACtEO,IAAM,aAAa,CAAC,WAA2B;AACpD,SAAO,OAAO,QAAQ,kCAAkC,KAAK;AAC/D;;;ACmCO,SAAS,aAAa,UAAyB,CAAC,GAAW;AAChE,QAAM,EAAE,QAAQ,QAAQ,SAAS,GAAG,IAAI;AAExC,QAAM,YAAsC;AAAA,IAC1C,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAEA,QAAM,oBAAoB,UAAU,KAAK;AAEzC,QAAM,aAAa,CAAC,SAA4B;AAC9C,QAAI,KAAK,WAAW,KAAK,KAAK,MAAM,CAAC,QAAQ,QAAQ,UAAa,QAAQ,IAAI,GAAG;AAC/E,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,KACf,IAAI,CAAC,QAAQ;AACZ,UAAI,eAAe,OAAO;AACxB,eAAO;AAAA,EAAK,IAAI,SAAS,IAAI,OAAO;AAAA,MACtC;AACA,UAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,eAAO;AAAA,EAAK,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1C;AACA,aAAO,IAAI,OAAO,GAAG,CAAC;AAAA,IACxB,CAAC,EACA,KAAK,EAAE;AAEV,WAAO,UAAU,SAAS;AAAA,EAC5B;AAEA,QAAM,YAAY,CAACC,WAA6B;AAC9C,WAAO,UAAUA,MAAK,KAAK;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,SAAS,aAAa;;;AClGnC,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AACd,QAAM,cAAc,aAAa;AAEjC,SAAO,UAAU,aAAa;AAC5B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,YAAM,QAAQ;AACd,UAAI,OAAO,gBAAgB,YAAY;AACrC,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAGA,YAAM,YAAY,KAAK,UAAU;AACjC,YAAM,eAAe,oBAAoB,KAAK,OAAO,IAAI;AACzD,YAAM,QAAQ,YAAY;AAC1B,iBAAW;AACX,aAAO;AAAA,QACL,qBAAqB,MAAM,OAAO,iBAAiB,MAAM,QAAQ,CAAC,CAAC,aAAa,OAAO,OAAO,UAAU;AAAA,MAC1G;AACA,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;ACvCO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;AAeO,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;;;ACvDO,SAAS,4BAA4B,SAAiB,aAAqB;AAChF,QAAM,MAAM,IAAI,IAAI,OAAO;AAC3B,QAAM,eAAe,IAAI,SAAS,QAAQ,WAAW;AACrD,SAAO,IAAI,UAAU,gBAAgB,IAAI,IAAI,SAAS,UAAU,GAAG,YAAY,IAAI,IAAI;AACzF;","names":["value","level"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@settlemint/sdk-utils",
3
3
  "description": "Shared utilities and helper functions for SettleMint SDK modules",
4
- "version": "2.3.2-prb7d863c7",
4
+ "version": "2.3.2-prbe16a4a1",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "FSL-1.1-MIT",