@settlemint/sdk-portal 2.3.2-pr8d084a79 → 2.3.2-pr8d2ec5b5

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
@@ -42,7 +42,6 @@
42
42
  - [HandleWalletVerificationChallengeOptions\<Setup\>](#handlewalletverificationchallengeoptionssetup)
43
43
  - [Transaction](#transaction)
44
44
  - [TransactionEvent](#transactionevent)
45
- - [TransactionReceipt](#transactionreceipt)
46
45
  - [WaitForTransactionReceiptOptions](#waitfortransactionreceiptoptions)
47
46
  - [WebsocketClientOptions](#websocketclientoptions)
48
47
  - [Type Aliases](#type-aliases)
@@ -682,7 +681,7 @@ const result = await portalClient.request(query);
682
681
 
683
682
  > **getWebsocketClient**(`options`): `Client`
684
683
 
685
- Defined in: [sdk/portal/src/utils/websocket-client.ts:30](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L30)
684
+ Defined in: [sdk/portal/src/utils/websocket-client.ts:23](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L23)
686
685
 
687
686
  Creates a GraphQL WebSocket client for the Portal API
688
687
 
@@ -698,24 +697,13 @@ Creates a GraphQL WebSocket client for the Portal API
698
697
 
699
698
  The GraphQL WebSocket client
700
699
 
701
- ##### Example
702
-
703
- ```ts
704
- import { getWebsocketClient } from "@settlemint/sdk-portal";
705
-
706
- const client = getWebsocketClient({
707
- portalGraphqlEndpoint: "https://portal.settlemint.com/graphql",
708
- accessToken: "your-access-token",
709
- });
710
- ```
711
-
712
700
  ***
713
701
 
714
702
  #### handleWalletVerificationChallenge()
715
703
 
716
704
  > **handleWalletVerificationChallenge**\<`Setup`\>(`options`): `Promise`\<\{ `challengeResponse`: `string`; `verificationId?`: `string`; \}\>
717
705
 
718
- Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:103](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L103)
706
+ Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:106](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L106)
719
707
 
720
708
  Handles a wallet verification challenge by generating an appropriate response
721
709
 
@@ -768,7 +756,7 @@ const result = await handleWalletVerificationChallenge({
768
756
 
769
757
  > **waitForTransactionReceipt**(`transactionHash`, `options`): `Promise`\<[`Transaction`](#transaction)\>
770
758
 
771
- Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:83](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L83)
759
+ Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:90](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L90)
772
760
 
773
761
  Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.
774
762
  This function polls until the transaction is confirmed or the timeout is reached.
@@ -806,80 +794,37 @@ const transaction = await waitForTransactionReceipt("0x123...", {
806
794
 
807
795
  #### HandleWalletVerificationChallengeOptions\<Setup\>
808
796
 
809
- Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:64](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L64)
797
+ Defined in: [sdk/portal/src/utils/wallet-verification-challenge.ts:73](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L73)
810
798
 
811
799
  Options for handling a wallet verification challenge
812
800
 
813
801
  ##### Type Parameters
814
802
 
815
- | Type Parameter |
816
- | ------ |
817
- | `Setup` *extends* `AbstractSetupSchema` |
818
-
819
- ##### Properties
820
-
821
- | Property | Type | Description | Defined in |
822
- | ------ | ------ | ------ | ------ |
823
- | <a id="code"></a> `code` | `string` \| `number` | The verification code provided by the user | [sdk/portal/src/utils/wallet-verification-challenge.ts:74](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L74) |
824
- | <a id="portalclient"></a> `portalClient` | `GraphQLClient` | The portal client instance | [sdk/portal/src/utils/wallet-verification-challenge.ts:66](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L66) |
825
- | <a id="portalgraphql"></a> `portalGraphql` | `initGraphQLTada`\<`Setup`\> | The GraphQL query builder | [sdk/portal/src/utils/wallet-verification-challenge.ts:68](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L68) |
826
- | <a id="userwalletaddress"></a> `userWalletAddress` | `` `0x${string}` `` | The wallet address to verify | [sdk/portal/src/utils/wallet-verification-challenge.ts:72](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L72) |
827
- | <a id="verificationid"></a> `verificationId` | `string` | The ID of the verification challenge | [sdk/portal/src/utils/wallet-verification-challenge.ts:70](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L70) |
828
- | <a id="verificationtype"></a> `verificationType` | `"otp"` \| `"secret-code"` \| `"pincode"` | The type of verification being performed | [sdk/portal/src/utils/wallet-verification-challenge.ts:76](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wallet-verification-challenge.ts#L76) |
803
+ | Type Parameter | Description |
804
+ | ------ | ------ |
805
+ | `Setup` *extends* `AbstractSetupSchema` | The GraphQL schema setup type |
829
806
 
830
807
  ***
831
808
 
832
809
  #### Transaction
833
810
 
834
- Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:37](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L37)
811
+ Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:43](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L43)
835
812
 
836
813
  Represents the structure of a blockchain transaction with its receipt
837
814
 
838
- ##### Properties
839
-
840
- | Property | Type | Description | Defined in |
841
- | ------ | ------ | ------ | ------ |
842
- | <a id="address"></a> `address` | `string` | The contract address involved in the transaction | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:46](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L46) |
843
- | <a id="createdat"></a> `createdAt` | `string` | Timestamp when the transaction was created | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:44](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L44) |
844
- | <a id="from"></a> `from` | `string` | The sender address (duplicate of receipt.from) | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:42](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L42) |
845
- | <a id="functionname"></a> `functionName` | `string` | The name of the function called in the transaction | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:48](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L48) |
846
- | <a id="iscontract"></a> `isContract` | `boolean` | Whether the transaction is a contract deployment | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:50](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L50) |
847
- | <a id="transactionhash"></a> `transactionHash` | `string` | The hash of the transaction (duplicate of receipt.transactionHash) | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:40](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L40) |
848
-
849
815
  ***
850
816
 
851
817
  #### TransactionEvent
852
818
 
853
- Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:14](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L14)
819
+ Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:15](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L15)
854
820
 
855
821
  Represents an event emitted during a transaction execution
856
822
 
857
823
  ***
858
824
 
859
- #### TransactionReceipt
860
-
861
- Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:23](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L23)
862
-
863
- Represents the structure of a blockchain transaction receipt
864
-
865
- ##### Extends
866
-
867
- - `TransactionReceipt`\<`string`, `number`, `"Success"` \| `"Reverted"`\>
868
-
869
- ##### Properties
870
-
871
- | Property | Type | Description | Overrides | Defined in |
872
- | ------ | ------ | ------ | ------ | ------ |
873
- | <a id="contractaddress"></a> `contractAddress` | `` `0x${string}` `` | The address of the contract deployed in the transaction | `TransactionReceiptViem.contractAddress` | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:31](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L31) |
874
- | <a id="events"></a> `events` | [`TransactionEvent`](#transactionevent)[] | Array of events emitted during the transaction | - | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:29](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L29) |
875
- | <a id="revertreason"></a> `revertReason` | `string` | The raw reason for transaction reversion, if applicable | - | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:25](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L25) |
876
- | <a id="revertreasondecoded"></a> `revertReasonDecoded` | `string` | Human-readable version of the revert reason | - | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:27](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L27) |
877
-
878
- ***
879
-
880
825
  #### WaitForTransactionReceiptOptions
881
826
 
882
- Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:60](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L60)
827
+ Defined in: [sdk/portal/src/utils/wait-for-transaction-receipt.ts:68](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L68)
883
828
 
884
829
  Options for waiting for a transaction receipt
885
830
 
@@ -887,19 +832,11 @@ Options for waiting for a transaction receipt
887
832
 
888
833
  - [`WebsocketClientOptions`](#websocketclientoptions)
889
834
 
890
- ##### Properties
891
-
892
- | Property | Type | Description | Inherited from | Defined in |
893
- | ------ | ------ | ------ | ------ | ------ |
894
- | <a id="accesstoken"></a> `accessToken` | `string` | The access token for authentication with the Portal API | [`WebsocketClientOptions`](#websocketclientoptions).[`accessToken`](#accesstoken-1) | [sdk/portal/src/utils/websocket-client.ts:14](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L14) |
895
- | <a id="portalgraphqlendpoint"></a> `portalGraphqlEndpoint` | `string` | The GraphQL endpoint URL for the Portal API | [`WebsocketClientOptions`](#websocketclientoptions).[`portalGraphqlEndpoint`](#portalgraphqlendpoint-1) | [sdk/portal/src/utils/websocket-client.ts:10](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L10) |
896
- | <a id="timeout"></a> `timeout?` | `number` | Optional timeout in milliseconds before the operation fails | - | [sdk/portal/src/utils/wait-for-transaction-receipt.ts:62](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/wait-for-transaction-receipt.ts#L62) |
897
-
898
835
  ***
899
836
 
900
837
  #### WebsocketClientOptions
901
838
 
902
- Defined in: [sdk/portal/src/utils/websocket-client.ts:6](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L6)
839
+ Defined in: [sdk/portal/src/utils/websocket-client.ts:10](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L10)
903
840
 
904
841
  Options for the GraphQL WebSocket client
905
842
 
@@ -907,13 +844,6 @@ Options for the GraphQL WebSocket client
907
844
 
908
845
  - [`WaitForTransactionReceiptOptions`](#waitfortransactionreceiptoptions)
909
846
 
910
- ##### Properties
911
-
912
- | Property | Type | Description | Defined in |
913
- | ------ | ------ | ------ | ------ |
914
- | <a id="accesstoken-1"></a> `accessToken` | `string` | The access token for authentication with the Portal API | [sdk/portal/src/utils/websocket-client.ts:14](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L14) |
915
- | <a id="portalgraphqlendpoint-1"></a> `portalGraphqlEndpoint` | `string` | The GraphQL endpoint URL for the Portal API | [sdk/portal/src/utils/websocket-client.ts:10](https://github.com/settlemint/sdk/blob/v2.3.2/sdk/portal/src/utils/websocket-client.ts#L10) |
916
-
917
847
  ### Type Aliases
918
848
 
919
849
  #### ClientOptions
package/dist/portal.cjs CHANGED
@@ -28,86 +28,12 @@ __export(portal_exports, {
28
28
  waitForTransactionReceipt: () => waitForTransactionReceipt
29
29
  });
30
30
  module.exports = __toCommonJS(portal_exports);
31
+ var import_http = require("@settlemint/sdk-utils/http");
31
32
  var import_runtime = require("@settlemint/sdk-utils/runtime");
32
33
  var import_validation = require("@settlemint/sdk-utils/validation");
33
34
  var import_gql = require("gql.tada");
34
35
  var import_graphql_request = require("graphql-request");
35
36
  var import_v4 = require("zod/v4");
36
- var import_gql2 = require("gql.tada");
37
-
38
- // src/utils/websocket-client.ts
39
- var import_graphql_ws = require("graphql-ws");
40
- function getWebsocketClient({ portalGraphqlEndpoint, accessToken }) {
41
- if (!portalGraphqlEndpoint) {
42
- throw new Error("portalGraphqlEndpoint is required");
43
- }
44
- if (!accessToken) {
45
- throw new Error("accessToken is required");
46
- }
47
- const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));
48
- return (0, import_graphql_ws.createClient)({
49
- url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`
50
- });
51
- }
52
- function setWsProtocol(url) {
53
- if (url.protocol === "ws:" || url.protocol === "wss:") {
54
- return url;
55
- }
56
- if (url.protocol === "http:") {
57
- url.protocol = "ws:";
58
- } else {
59
- url.protocol = "wss:";
60
- }
61
- return url;
62
- }
63
-
64
- // src/utils/wait-for-transaction-receipt.ts
65
- async function waitForTransactionReceipt(transactionHash, options) {
66
- const wsClient = getWebsocketClient(options);
67
- const subscription = wsClient.iterate({
68
- query: `subscription getTransaction($transactionHash: String!) {
69
- getTransaction(transactionHash: $transactionHash) {
70
- receipt {
71
- transactionHash
72
- to
73
- status
74
- from
75
- type
76
- revertReason
77
- revertReasonDecoded
78
- logs
79
- events
80
- contractAddress
81
- }
82
- transactionHash
83
- from
84
- createdAt
85
- address
86
- functionName
87
- isContract
88
- }
89
- }`,
90
- variables: { transactionHash }
91
- });
92
- const promises = [getTransactionFromSubscription(subscription)];
93
- if (options.timeout) {
94
- promises.push(createTimeoutPromise(options.timeout));
95
- }
96
- return Promise.race(promises);
97
- }
98
- function createTimeoutPromise(timeout) {
99
- return new Promise((_, reject) => {
100
- setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
101
- });
102
- }
103
- async function getTransactionFromSubscription(subscription) {
104
- for await (const result of subscription) {
105
- if (result?.data?.getTransaction?.receipt) {
106
- return result.data.getTransaction;
107
- }
108
- }
109
- throw new Error("No transaction found");
110
- }
111
37
 
112
38
  // src/utils/wallet-verification-challenge.ts
113
39
  var import_node_crypto = require("crypto");
@@ -187,10 +113,85 @@ async function handleWalletVerificationChallenge({
187
113
  }
188
114
  }
189
115
 
116
+ // src/utils/websocket-client.ts
117
+ var import_graphql_ws = require("graphql-ws");
118
+ function getWebsocketClient({ portalGraphqlEndpoint, accessToken }) {
119
+ if (!portalGraphqlEndpoint) {
120
+ throw new Error("portalGraphqlEndpoint is required");
121
+ }
122
+ if (!accessToken) {
123
+ throw new Error("accessToken is required");
124
+ }
125
+ const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));
126
+ return (0, import_graphql_ws.createClient)({
127
+ url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`
128
+ });
129
+ }
130
+ function setWsProtocol(url) {
131
+ if (url.protocol === "ws:" || url.protocol === "wss:") {
132
+ return url;
133
+ }
134
+ if (url.protocol === "http:") {
135
+ url.protocol = "ws:";
136
+ } else {
137
+ url.protocol = "wss:";
138
+ }
139
+ return url;
140
+ }
141
+
142
+ // src/utils/wait-for-transaction-receipt.ts
143
+ async function waitForTransactionReceipt(transactionHash, options) {
144
+ const wsClient = getWebsocketClient(options);
145
+ const subscription = wsClient.iterate({
146
+ query: `subscription getTransaction($transactionHash: String!) {
147
+ getTransaction(transactionHash: $transactionHash) {
148
+ receipt {
149
+ transactionHash
150
+ to
151
+ status
152
+ from
153
+ type
154
+ revertReason
155
+ revertReasonDecoded
156
+ logs
157
+ events
158
+ contractAddress
159
+ }
160
+ transactionHash
161
+ from
162
+ createdAt
163
+ address
164
+ functionName
165
+ isContract
166
+ }
167
+ }`,
168
+ variables: { transactionHash }
169
+ });
170
+ const promises = [getTransactionFromSubscription(subscription)];
171
+ if (options.timeout) {
172
+ promises.push(createTimeoutPromise(options.timeout));
173
+ }
174
+ return Promise.race(promises);
175
+ }
176
+ function createTimeoutPromise(timeout) {
177
+ return new Promise((_, reject) => {
178
+ setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
179
+ });
180
+ }
181
+ async function getTransactionFromSubscription(subscription) {
182
+ for await (const result of subscription) {
183
+ if (result?.data?.getTransaction?.receipt) {
184
+ return result.data.getTransaction;
185
+ }
186
+ }
187
+ throw new Error("No transaction found");
188
+ }
189
+
190
190
  // src/portal.ts
191
+ var import_gql2 = require("gql.tada");
191
192
  var ClientOptionsSchema = import_v4.z.object({
192
193
  instance: import_validation.UrlOrPathSchema,
193
- accessToken: import_validation.ApplicationAccessTokenSchema,
194
+ accessToken: import_validation.ApplicationAccessTokenSchema.optional(),
194
195
  cache: import_v4.z.enum(["default", "force-cache", "no-cache", "no-store", "only-if-cached", "reload"]).optional()
195
196
  });
196
197
  function createPortalClient(options, clientOptions) {
@@ -201,7 +202,7 @@ function createPortalClient(options, clientOptions) {
201
202
  return {
202
203
  client: new import_graphql_request.GraphQLClient(fullUrl, {
203
204
  ...clientOptions,
204
- headers: { ...clientOptions?.headers ?? {}, "x-auth-token": validatedOptions.accessToken }
205
+ headers: (0, import_http.appendHeaders)(clientOptions?.headers, { "x-auth-token": validatedOptions.accessToken })
205
206
  }),
206
207
  graphql
207
208
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/portal.ts","../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts"],"sourcesContent":["import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod/v4\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport {\n waitForTransactionReceipt,\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n","import { createClient } from \"graphql-ws\";\n\n/**\n * Options for the GraphQL WebSocket client\n */\nexport interface WebsocketClientOptions {\n /**\n * The GraphQL endpoint URL for the Portal API\n */\n portalGraphqlEndpoint: string;\n /**\n * The access token for authentication with the Portal API\n */\n accessToken: string;\n}\n\n/**\n * Creates a GraphQL WebSocket client for the Portal API\n *\n * @param {WebsocketClientOptions} options - The options for the client\n * @returns {Client} The GraphQL WebSocket client\n * @example\n * import { getWebsocketClient } from \"@settlemint/sdk-portal\";\n *\n * const client = getWebsocketClient({\n * portalGraphqlEndpoint: \"https://portal.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * });\n */\nexport function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions) {\n if (!portalGraphqlEndpoint) {\n throw new Error(\"portalGraphqlEndpoint is required\");\n }\n if (!accessToken) {\n throw new Error(\"accessToken is required\");\n }\n const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`,\n });\n}\n\nfunction setWsProtocol(url: URL) {\n if (url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return url;\n }\n if (url.protocol === \"http:\") {\n url.protocol = \"ws:\";\n } else {\n url.protocol = \"wss:\";\n }\n return url;\n}\n","import type { FormattedExecutionResult } from \"graphql-ws\";\nimport type { Address, Hex, TransactionReceipt as TransactionReceiptViem } from \"viem\";\nimport { type WebsocketClientOptions, getWebsocketClient } from \"./websocket-client.js\";\n\n/**\n * Represents an event emitted during a transaction execution\n *\n * @typedef {Object} TransactionEvent\n * @property {string} eventName - The name of the event that was emitted\n * @property {Record<string, unknown>} args - The arguments emitted by the event\n * @property {Hex[]} topics - Indexed event parameters used for filtering and searching\n */\n\nexport interface TransactionEvent {\n eventName: string;\n args: Record<string, unknown>;\n topics: Hex[];\n}\n\n/**\n * Represents the structure of a blockchain transaction receipt\n */\nexport interface TransactionReceipt extends TransactionReceiptViem<string, number, \"Success\" | \"Reverted\"> {\n /** The raw reason for transaction reversion, if applicable */\n revertReason: string;\n /** Human-readable version of the revert reason */\n revertReasonDecoded: string;\n /** Array of events emitted during the transaction */\n events: TransactionEvent[];\n /** The address of the contract deployed in the transaction */\n contractAddress: Address;\n}\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n */\nexport interface Transaction {\n receipt: TransactionReceipt;\n /** The hash of the transaction (duplicate of receipt.transactionHash) */\n transactionHash: string;\n /** The sender address (duplicate of receipt.from) */\n from: string;\n /** Timestamp when the transaction was created */\n createdAt: string;\n /** The contract address involved in the transaction */\n address: string;\n /** The name of the function called in the transaction */\n functionName: string;\n /** Whether the transaction is a contract deployment */\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Options for waiting for a transaction receipt\n */\nexport interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {\n /** Optional timeout in milliseconds before the operation fails */\n timeout?: number;\n}\n\n/**\n * Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.\n * This function polls until the transaction is confirmed or the timeout is reached.\n *\n * @param transactionHash - The hash of the transaction to wait for\n * @param options - Configuration options for the waiting process\n * @returns The transaction details including receipt information when the transaction is confirmed\n * @throws Error if the transaction receipt cannot be retrieved within the specified timeout\n *\n * @example\n * import { waitForTransactionReceipt } from \"@settlemint/sdk-portal\";\n *\n * const transaction = await waitForTransactionReceipt(\"0x123...\", {\n * portalGraphqlEndpoint: \"https://example.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * timeout: 30000 // 30 seconds timeout\n * });\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = getWebsocketClient(options);\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n /** The portal client instance */\n portalClient: GraphQLClient;\n /** The GraphQL query builder */\n portalGraphql: initGraphQLTada<Setup>;\n /** The ID of the verification challenge */\n verificationId: string;\n /** The wallet address to verify */\n userWalletAddress: Address;\n /** The verification code provided by the user */\n code: string | number;\n /** The type of verification being performed */\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n"],"mappings":"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","names":["import_gql"]}
1
+ {"version":3,"sources":["../src/portal.ts","../src/utils/wallet-verification-challenge.ts","../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts"],"sourcesContent":["import { appendHeaders } from \"@settlemint/sdk-utils/http\";\nimport { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod/v4\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema.optional(),\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: appendHeaders(clientOptions?.headers, { \"x-auth-token\": validatedOptions.accessToken }),\n }),\n graphql,\n };\n}\n\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport {\n waitForTransactionReceipt,\n type WaitForTransactionReceiptOptions,\n type Transaction,\n type TransactionEvent,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n *\n * @typedef {Object} HandleWalletVerificationChallengeOptions\n * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type\n * @property {GraphQLClient} portalClient - The portal client instance\n * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder\n * @property {string} verificationId - The ID of the verification challenge\n * @property {Address} userWalletAddress - The wallet address to verify\n * @property {string | number} code - The verification code provided by the user\n * @property {\"otp\" | \"secret-code\" | \"pincode\"} verificationType - The type of verification being performed\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n portalClient: GraphQLClient;\n portalGraphql: initGraphQLTada<Setup>;\n verificationId: string;\n userWalletAddress: Address;\n code: string | number;\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n","import { createClient } from \"graphql-ws\";\n\n/**\n * Options for the GraphQL WebSocket client\n *\n * @typedef {Object} WebsocketClientOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n */\nexport interface WebsocketClientOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n}\n\n/**\n * Creates a GraphQL WebSocket client for the Portal API\n *\n * @param {WebsocketClientOptions} options - The options for the client\n * @param {string} options.portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @param {string} options.accessToken - The access token for authentication with the Portal API\n * @returns {Client} The GraphQL WebSocket client\n */\nexport function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions) {\n if (!portalGraphqlEndpoint) {\n throw new Error(\"portalGraphqlEndpoint is required\");\n }\n if (!accessToken) {\n throw new Error(\"accessToken is required\");\n }\n const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`,\n });\n}\n\nfunction setWsProtocol(url: URL) {\n if (url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return url;\n }\n if (url.protocol === \"http:\") {\n url.protocol = \"ws:\";\n } else {\n url.protocol = \"wss:\";\n }\n return url;\n}\n","import type { FormattedExecutionResult } from \"graphql-ws\";\nimport { type WebsocketClientOptions, getWebsocketClient } from \"./websocket-client.js\";\n\nimport type { Hex, TransactionReceipt } from \"viem\";\n\n/**\n * Represents an event emitted during a transaction execution\n *\n * @typedef {Object} TransactionEvent\n * @property {string} eventName - The name of the event that was emitted\n * @property {Record<string, unknown>} args - The arguments emitted by the event\n * @property {Hex[]} topics - Indexed event parameters used for filtering and searching\n */\n\nexport interface TransactionEvent {\n eventName: string;\n args: Record<string, unknown>;\n topics: Hex[];\n}\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n *\n * @typedef {Object} Transaction\n * @property {Object} receipt - The transaction receipt details\n * @property {string} receipt.transactionHash - The hash of the transaction\n * @property {string} receipt.to - The recipient address of the transaction\n * @property {string} receipt.status - The status of the transaction (success/failure)\n * @property {string} receipt.from - The sender address of the transaction\n * @property {string} receipt.type - The type of the transaction\n * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable\n * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason\n * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction\n * @property {string[]} receipt.logs - Array of log entries generated by the transaction\n * @property {TransactionEvent[]} receipt.events - Array of events emitted during the transaction\n * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)\n * @property {string} from - The sender address (duplicate of receipt.from)\n * @property {string} createdAt - Timestamp when the transaction was created\n * @property {string} address - The contract address involved in the transaction\n * @property {string} functionName - The name of the function called in the transaction\n * @property {boolean} isContract - Whether the transaction is a contract deployment\n */\nexport interface Transaction {\n receipt: TransactionReceipt<string, number, \"Success\" | \"Reverted\"> & {\n revertReason: string;\n revertReasonDecoded: string;\n events: TransactionEvent[];\n contractAddress: string;\n };\n transactionHash: string;\n from: string;\n createdAt: string;\n address: string;\n functionName: string;\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\nexport interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {\n timeout?: number;\n}\n\n/**\n * Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.\n * This function polls until the transaction is confirmed or the timeout is reached.\n *\n * @param transactionHash - The hash of the transaction to wait for\n * @param options - Configuration options for the waiting process\n * @returns The transaction details including receipt information when the transaction is confirmed\n * @throws Error if the transaction receipt cannot be retrieved within the specified timeout\n *\n * @example\n * import { waitForTransactionReceipt } from \"@settlemint/sdk-portal\";\n *\n * const transaction = await waitForTransactionReceipt(\"0x123...\", {\n * portalGraphqlEndpoint: \"https://example.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * timeout: 30000 // 30 seconds timeout\n * });\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = getWebsocketClient(options);\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n"],"mappings":"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","names":["import_gql"]}
package/dist/portal.d.cts CHANGED
@@ -2,34 +2,76 @@ import { AbstractSetupSchema, initGraphQLTada } from 'gql.tada';
2
2
  export { FragmentOf, ResultOf, VariablesOf, readFragment } from 'gql.tada';
3
3
  import { GraphQLClient } from 'graphql-request';
4
4
  import { z } from 'zod/v4';
5
- import { TransactionReceipt as TransactionReceipt$1, Hex, Address } from 'viem';
5
+ import { Address, TransactionReceipt, Hex } from 'viem';
6
6
  import * as graphql_ws from 'graphql-ws';
7
7
 
8
+ /**
9
+ * Options for handling a wallet verification challenge
10
+ *
11
+ * @typedef {Object} HandleWalletVerificationChallengeOptions
12
+ * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
13
+ * @property {GraphQLClient} portalClient - The portal client instance
14
+ * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
15
+ * @property {string} verificationId - The ID of the verification challenge
16
+ * @property {Address} userWalletAddress - The wallet address to verify
17
+ * @property {string | number} code - The verification code provided by the user
18
+ * @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
19
+ */
20
+ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
21
+ portalClient: GraphQLClient;
22
+ portalGraphql: initGraphQLTada<Setup>;
23
+ verificationId: string;
24
+ userWalletAddress: Address;
25
+ code: string | number;
26
+ verificationType: "otp" | "secret-code" | "pincode";
27
+ }
28
+ /**
29
+ * Handles a wallet verification challenge by generating an appropriate response
30
+ *
31
+ * @param options - The options for handling the wallet verification challenge
32
+ * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
33
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
34
+ * @example
35
+ * import { createPortalClient } from "@settlemint/sdk-portal";
36
+ * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
37
+ *
38
+ * const { client, graphql } = createPortalClient({
39
+ * instance: "https://portal.example.com/graphql",
40
+ * accessToken: "your-access-token"
41
+ * });
42
+ *
43
+ * const result = await handleWalletVerificationChallenge({
44
+ * portalClient: client,
45
+ * portalGraphql: graphql,
46
+ * verificationId: "verification-123",
47
+ * userWalletAddress: "0x123...",
48
+ * code: "123456",
49
+ * verificationType: "otp"
50
+ * });
51
+ */
52
+ declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
53
+ challengeResponse: string;
54
+ verificationId?: string;
55
+ }>;
56
+
8
57
  /**
9
58
  * Options for the GraphQL WebSocket client
59
+ *
60
+ * @typedef {Object} WebsocketClientOptions
61
+ * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
62
+ * @property {string} accessToken - The access token for authentication with the Portal API
10
63
  */
11
64
  interface WebsocketClientOptions {
12
- /**
13
- * The GraphQL endpoint URL for the Portal API
14
- */
15
65
  portalGraphqlEndpoint: string;
16
- /**
17
- * The access token for authentication with the Portal API
18
- */
19
66
  accessToken: string;
20
67
  }
21
68
  /**
22
69
  * Creates a GraphQL WebSocket client for the Portal API
23
70
  *
24
71
  * @param {WebsocketClientOptions} options - The options for the client
72
+ * @param {string} options.portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
73
+ * @param {string} options.accessToken - The access token for authentication with the Portal API
25
74
  * @returns {Client} The GraphQL WebSocket client
26
- * @example
27
- * import { getWebsocketClient } from "@settlemint/sdk-portal";
28
- *
29
- * const client = getWebsocketClient({
30
- * portalGraphqlEndpoint: "https://portal.settlemint.com/graphql",
31
- * accessToken: "your-access-token",
32
- * });
33
75
  */
34
76
  declare function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions): graphql_ws.Client;
35
77
 
@@ -46,42 +88,49 @@ interface TransactionEvent {
46
88
  args: Record<string, unknown>;
47
89
  topics: Hex[];
48
90
  }
49
- /**
50
- * Represents the structure of a blockchain transaction receipt
51
- */
52
- interface TransactionReceipt extends TransactionReceipt$1<string, number, "Success" | "Reverted"> {
53
- /** The raw reason for transaction reversion, if applicable */
54
- revertReason: string;
55
- /** Human-readable version of the revert reason */
56
- revertReasonDecoded: string;
57
- /** Array of events emitted during the transaction */
58
- events: TransactionEvent[];
59
- /** The address of the contract deployed in the transaction */
60
- contractAddress: Address;
61
- }
62
91
  /**
63
92
  * Represents the structure of a blockchain transaction with its receipt
93
+ *
94
+ * @typedef {Object} Transaction
95
+ * @property {Object} receipt - The transaction receipt details
96
+ * @property {string} receipt.transactionHash - The hash of the transaction
97
+ * @property {string} receipt.to - The recipient address of the transaction
98
+ * @property {string} receipt.status - The status of the transaction (success/failure)
99
+ * @property {string} receipt.from - The sender address of the transaction
100
+ * @property {string} receipt.type - The type of the transaction
101
+ * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
102
+ * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
103
+ * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
104
+ * @property {string[]} receipt.logs - Array of log entries generated by the transaction
105
+ * @property {TransactionEvent[]} receipt.events - Array of events emitted during the transaction
106
+ * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
107
+ * @property {string} from - The sender address (duplicate of receipt.from)
108
+ * @property {string} createdAt - Timestamp when the transaction was created
109
+ * @property {string} address - The contract address involved in the transaction
110
+ * @property {string} functionName - The name of the function called in the transaction
111
+ * @property {boolean} isContract - Whether the transaction is a contract deployment
64
112
  */
65
113
  interface Transaction {
66
- receipt: TransactionReceipt;
67
- /** The hash of the transaction (duplicate of receipt.transactionHash) */
114
+ receipt: TransactionReceipt<string, number, "Success" | "Reverted"> & {
115
+ revertReason: string;
116
+ revertReasonDecoded: string;
117
+ events: TransactionEvent[];
118
+ contractAddress: string;
119
+ };
68
120
  transactionHash: string;
69
- /** The sender address (duplicate of receipt.from) */
70
121
  from: string;
71
- /** Timestamp when the transaction was created */
72
122
  createdAt: string;
73
- /** The contract address involved in the transaction */
74
123
  address: string;
75
- /** The name of the function called in the transaction */
76
124
  functionName: string;
77
- /** Whether the transaction is a contract deployment */
78
125
  isContract: boolean;
79
126
  }
80
127
  /**
81
128
  * Options for waiting for a transaction receipt
129
+ *
130
+ * @typedef {Object} WaitForTransactionReceiptOptions
131
+ * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails
82
132
  */
83
133
  interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
84
- /** Optional timeout in milliseconds before the operation fails */
85
134
  timeout?: number;
86
135
  }
87
136
  /**
@@ -104,52 +153,6 @@ interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
104
153
  */
105
154
  declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
106
155
 
107
- /**
108
- * Options for handling a wallet verification challenge
109
- */
110
- interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
111
- /** The portal client instance */
112
- portalClient: GraphQLClient;
113
- /** The GraphQL query builder */
114
- portalGraphql: initGraphQLTada<Setup>;
115
- /** The ID of the verification challenge */
116
- verificationId: string;
117
- /** The wallet address to verify */
118
- userWalletAddress: Address;
119
- /** The verification code provided by the user */
120
- code: string | number;
121
- /** The type of verification being performed */
122
- verificationType: "otp" | "secret-code" | "pincode";
123
- }
124
- /**
125
- * Handles a wallet verification challenge by generating an appropriate response
126
- *
127
- * @param options - The options for handling the wallet verification challenge
128
- * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
129
- * @throws {ChallengeError} If the challenge cannot be created or is invalid
130
- * @example
131
- * import { createPortalClient } from "@settlemint/sdk-portal";
132
- * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
133
- *
134
- * const { client, graphql } = createPortalClient({
135
- * instance: "https://portal.example.com/graphql",
136
- * accessToken: "your-access-token"
137
- * });
138
- *
139
- * const result = await handleWalletVerificationChallenge({
140
- * portalClient: client,
141
- * portalGraphql: graphql,
142
- * verificationId: "verification-123",
143
- * userWalletAddress: "0x123...",
144
- * code: "123456",
145
- * verificationType: "otp"
146
- * });
147
- */
148
- declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
149
- challengeResponse: string;
150
- verificationId?: string;
151
- }>;
152
-
153
156
  /**
154
157
  * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
155
158
  */
@@ -159,7 +162,7 @@ type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];
159
162
  */
160
163
  declare const ClientOptionsSchema: z.ZodObject<{
161
164
  instance: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
162
- accessToken: z.ZodString;
165
+ accessToken: z.ZodOptional<z.ZodString>;
163
166
  cache: z.ZodOptional<z.ZodEnum<{
164
167
  default: "default";
165
168
  "force-cache": "force-cache";
@@ -223,4 +226,4 @@ declare function createPortalClient<const Setup extends AbstractSetupSchema>(opt
223
226
  graphql: initGraphQLTada<Setup>;
224
227
  };
225
228
 
226
- export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type TransactionEvent, type TransactionReceipt, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
229
+ export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type TransactionEvent, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
package/dist/portal.d.ts CHANGED
@@ -2,34 +2,76 @@ import { AbstractSetupSchema, initGraphQLTada } from 'gql.tada';
2
2
  export { FragmentOf, ResultOf, VariablesOf, readFragment } from 'gql.tada';
3
3
  import { GraphQLClient } from 'graphql-request';
4
4
  import { z } from 'zod/v4';
5
- import { TransactionReceipt as TransactionReceipt$1, Hex, Address } from 'viem';
5
+ import { Address, TransactionReceipt, Hex } from 'viem';
6
6
  import * as graphql_ws from 'graphql-ws';
7
7
 
8
+ /**
9
+ * Options for handling a wallet verification challenge
10
+ *
11
+ * @typedef {Object} HandleWalletVerificationChallengeOptions
12
+ * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type
13
+ * @property {GraphQLClient} portalClient - The portal client instance
14
+ * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder
15
+ * @property {string} verificationId - The ID of the verification challenge
16
+ * @property {Address} userWalletAddress - The wallet address to verify
17
+ * @property {string | number} code - The verification code provided by the user
18
+ * @property {"otp" | "secret-code" | "pincode"} verificationType - The type of verification being performed
19
+ */
20
+ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
21
+ portalClient: GraphQLClient;
22
+ portalGraphql: initGraphQLTada<Setup>;
23
+ verificationId: string;
24
+ userWalletAddress: Address;
25
+ code: string | number;
26
+ verificationType: "otp" | "secret-code" | "pincode";
27
+ }
28
+ /**
29
+ * Handles a wallet verification challenge by generating an appropriate response
30
+ *
31
+ * @param options - The options for handling the wallet verification challenge
32
+ * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
33
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
34
+ * @example
35
+ * import { createPortalClient } from "@settlemint/sdk-portal";
36
+ * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
37
+ *
38
+ * const { client, graphql } = createPortalClient({
39
+ * instance: "https://portal.example.com/graphql",
40
+ * accessToken: "your-access-token"
41
+ * });
42
+ *
43
+ * const result = await handleWalletVerificationChallenge({
44
+ * portalClient: client,
45
+ * portalGraphql: graphql,
46
+ * verificationId: "verification-123",
47
+ * userWalletAddress: "0x123...",
48
+ * code: "123456",
49
+ * verificationType: "otp"
50
+ * });
51
+ */
52
+ declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
53
+ challengeResponse: string;
54
+ verificationId?: string;
55
+ }>;
56
+
8
57
  /**
9
58
  * Options for the GraphQL WebSocket client
59
+ *
60
+ * @typedef {Object} WebsocketClientOptions
61
+ * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
62
+ * @property {string} accessToken - The access token for authentication with the Portal API
10
63
  */
11
64
  interface WebsocketClientOptions {
12
- /**
13
- * The GraphQL endpoint URL for the Portal API
14
- */
15
65
  portalGraphqlEndpoint: string;
16
- /**
17
- * The access token for authentication with the Portal API
18
- */
19
66
  accessToken: string;
20
67
  }
21
68
  /**
22
69
  * Creates a GraphQL WebSocket client for the Portal API
23
70
  *
24
71
  * @param {WebsocketClientOptions} options - The options for the client
72
+ * @param {string} options.portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API
73
+ * @param {string} options.accessToken - The access token for authentication with the Portal API
25
74
  * @returns {Client} The GraphQL WebSocket client
26
- * @example
27
- * import { getWebsocketClient } from "@settlemint/sdk-portal";
28
- *
29
- * const client = getWebsocketClient({
30
- * portalGraphqlEndpoint: "https://portal.settlemint.com/graphql",
31
- * accessToken: "your-access-token",
32
- * });
33
75
  */
34
76
  declare function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions): graphql_ws.Client;
35
77
 
@@ -46,42 +88,49 @@ interface TransactionEvent {
46
88
  args: Record<string, unknown>;
47
89
  topics: Hex[];
48
90
  }
49
- /**
50
- * Represents the structure of a blockchain transaction receipt
51
- */
52
- interface TransactionReceipt extends TransactionReceipt$1<string, number, "Success" | "Reverted"> {
53
- /** The raw reason for transaction reversion, if applicable */
54
- revertReason: string;
55
- /** Human-readable version of the revert reason */
56
- revertReasonDecoded: string;
57
- /** Array of events emitted during the transaction */
58
- events: TransactionEvent[];
59
- /** The address of the contract deployed in the transaction */
60
- contractAddress: Address;
61
- }
62
91
  /**
63
92
  * Represents the structure of a blockchain transaction with its receipt
93
+ *
94
+ * @typedef {Object} Transaction
95
+ * @property {Object} receipt - The transaction receipt details
96
+ * @property {string} receipt.transactionHash - The hash of the transaction
97
+ * @property {string} receipt.to - The recipient address of the transaction
98
+ * @property {string} receipt.status - The status of the transaction (success/failure)
99
+ * @property {string} receipt.from - The sender address of the transaction
100
+ * @property {string} receipt.type - The type of the transaction
101
+ * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable
102
+ * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason
103
+ * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction
104
+ * @property {string[]} receipt.logs - Array of log entries generated by the transaction
105
+ * @property {TransactionEvent[]} receipt.events - Array of events emitted during the transaction
106
+ * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)
107
+ * @property {string} from - The sender address (duplicate of receipt.from)
108
+ * @property {string} createdAt - Timestamp when the transaction was created
109
+ * @property {string} address - The contract address involved in the transaction
110
+ * @property {string} functionName - The name of the function called in the transaction
111
+ * @property {boolean} isContract - Whether the transaction is a contract deployment
64
112
  */
65
113
  interface Transaction {
66
- receipt: TransactionReceipt;
67
- /** The hash of the transaction (duplicate of receipt.transactionHash) */
114
+ receipt: TransactionReceipt<string, number, "Success" | "Reverted"> & {
115
+ revertReason: string;
116
+ revertReasonDecoded: string;
117
+ events: TransactionEvent[];
118
+ contractAddress: string;
119
+ };
68
120
  transactionHash: string;
69
- /** The sender address (duplicate of receipt.from) */
70
121
  from: string;
71
- /** Timestamp when the transaction was created */
72
122
  createdAt: string;
73
- /** The contract address involved in the transaction */
74
123
  address: string;
75
- /** The name of the function called in the transaction */
76
124
  functionName: string;
77
- /** Whether the transaction is a contract deployment */
78
125
  isContract: boolean;
79
126
  }
80
127
  /**
81
128
  * Options for waiting for a transaction receipt
129
+ *
130
+ * @typedef {Object} WaitForTransactionReceiptOptions
131
+ * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails
82
132
  */
83
133
  interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
84
- /** Optional timeout in milliseconds before the operation fails */
85
134
  timeout?: number;
86
135
  }
87
136
  /**
@@ -104,52 +153,6 @@ interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
104
153
  */
105
154
  declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
106
155
 
107
- /**
108
- * Options for handling a wallet verification challenge
109
- */
110
- interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {
111
- /** The portal client instance */
112
- portalClient: GraphQLClient;
113
- /** The GraphQL query builder */
114
- portalGraphql: initGraphQLTada<Setup>;
115
- /** The ID of the verification challenge */
116
- verificationId: string;
117
- /** The wallet address to verify */
118
- userWalletAddress: Address;
119
- /** The verification code provided by the user */
120
- code: string | number;
121
- /** The type of verification being performed */
122
- verificationType: "otp" | "secret-code" | "pincode";
123
- }
124
- /**
125
- * Handles a wallet verification challenge by generating an appropriate response
126
- *
127
- * @param options - The options for handling the wallet verification challenge
128
- * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
129
- * @throws {ChallengeError} If the challenge cannot be created or is invalid
130
- * @example
131
- * import { createPortalClient } from "@settlemint/sdk-portal";
132
- * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
133
- *
134
- * const { client, graphql } = createPortalClient({
135
- * instance: "https://portal.example.com/graphql",
136
- * accessToken: "your-access-token"
137
- * });
138
- *
139
- * const result = await handleWalletVerificationChallenge({
140
- * portalClient: client,
141
- * portalGraphql: graphql,
142
- * verificationId: "verification-123",
143
- * userWalletAddress: "0x123...",
144
- * code: "123456",
145
- * verificationType: "otp"
146
- * });
147
- */
148
- declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
149
- challengeResponse: string;
150
- verificationId?: string;
151
- }>;
152
-
153
156
  /**
154
157
  * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.
155
158
  */
@@ -159,7 +162,7 @@ type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];
159
162
  */
160
163
  declare const ClientOptionsSchema: z.ZodObject<{
161
164
  instance: z.ZodUnion<readonly [z.ZodString, z.ZodString]>;
162
- accessToken: z.ZodString;
165
+ accessToken: z.ZodOptional<z.ZodString>;
163
166
  cache: z.ZodOptional<z.ZodEnum<{
164
167
  default: "default";
165
168
  "force-cache": "force-cache";
@@ -223,4 +226,4 @@ declare function createPortalClient<const Setup extends AbstractSetupSchema>(opt
223
226
  graphql: initGraphQLTada<Setup>;
224
227
  };
225
228
 
226
- export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type TransactionEvent, type TransactionReceipt, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
229
+ export { type ClientOptions, ClientOptionsSchema, type HandleWalletVerificationChallengeOptions, type RequestConfig, type Transaction, type TransactionEvent, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, waitForTransactionReceipt };
package/dist/portal.mjs CHANGED
@@ -1,84 +1,10 @@
1
1
  // src/portal.ts
2
+ import { appendHeaders } from "@settlemint/sdk-utils/http";
2
3
  import { ensureServer } from "@settlemint/sdk-utils/runtime";
3
4
  import { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from "@settlemint/sdk-utils/validation";
4
5
  import { initGraphQLTada } from "gql.tada";
5
6
  import { GraphQLClient } from "graphql-request";
6
7
  import { z } from "zod/v4";
7
- import { readFragment } from "gql.tada";
8
-
9
- // src/utils/websocket-client.ts
10
- import { createClient } from "graphql-ws";
11
- function getWebsocketClient({ portalGraphqlEndpoint, accessToken }) {
12
- if (!portalGraphqlEndpoint) {
13
- throw new Error("portalGraphqlEndpoint is required");
14
- }
15
- if (!accessToken) {
16
- throw new Error("accessToken is required");
17
- }
18
- const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));
19
- return createClient({
20
- url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`
21
- });
22
- }
23
- function setWsProtocol(url) {
24
- if (url.protocol === "ws:" || url.protocol === "wss:") {
25
- return url;
26
- }
27
- if (url.protocol === "http:") {
28
- url.protocol = "ws:";
29
- } else {
30
- url.protocol = "wss:";
31
- }
32
- return url;
33
- }
34
-
35
- // src/utils/wait-for-transaction-receipt.ts
36
- async function waitForTransactionReceipt(transactionHash, options) {
37
- const wsClient = getWebsocketClient(options);
38
- const subscription = wsClient.iterate({
39
- query: `subscription getTransaction($transactionHash: String!) {
40
- getTransaction(transactionHash: $transactionHash) {
41
- receipt {
42
- transactionHash
43
- to
44
- status
45
- from
46
- type
47
- revertReason
48
- revertReasonDecoded
49
- logs
50
- events
51
- contractAddress
52
- }
53
- transactionHash
54
- from
55
- createdAt
56
- address
57
- functionName
58
- isContract
59
- }
60
- }`,
61
- variables: { transactionHash }
62
- });
63
- const promises = [getTransactionFromSubscription(subscription)];
64
- if (options.timeout) {
65
- promises.push(createTimeoutPromise(options.timeout));
66
- }
67
- return Promise.race(promises);
68
- }
69
- function createTimeoutPromise(timeout) {
70
- return new Promise((_, reject) => {
71
- setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
72
- });
73
- }
74
- async function getTransactionFromSubscription(subscription) {
75
- for await (const result of subscription) {
76
- if (result?.data?.getTransaction?.receipt) {
77
- return result.data.getTransaction;
78
- }
79
- }
80
- throw new Error("No transaction found");
81
- }
82
8
 
83
9
  // src/utils/wallet-verification-challenge.ts
84
10
  import { createHash } from "crypto";
@@ -158,10 +84,85 @@ async function handleWalletVerificationChallenge({
158
84
  }
159
85
  }
160
86
 
87
+ // src/utils/websocket-client.ts
88
+ import { createClient } from "graphql-ws";
89
+ function getWebsocketClient({ portalGraphqlEndpoint, accessToken }) {
90
+ if (!portalGraphqlEndpoint) {
91
+ throw new Error("portalGraphqlEndpoint is required");
92
+ }
93
+ if (!accessToken) {
94
+ throw new Error("accessToken is required");
95
+ }
96
+ const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));
97
+ return createClient({
98
+ url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`
99
+ });
100
+ }
101
+ function setWsProtocol(url) {
102
+ if (url.protocol === "ws:" || url.protocol === "wss:") {
103
+ return url;
104
+ }
105
+ if (url.protocol === "http:") {
106
+ url.protocol = "ws:";
107
+ } else {
108
+ url.protocol = "wss:";
109
+ }
110
+ return url;
111
+ }
112
+
113
+ // src/utils/wait-for-transaction-receipt.ts
114
+ async function waitForTransactionReceipt(transactionHash, options) {
115
+ const wsClient = getWebsocketClient(options);
116
+ const subscription = wsClient.iterate({
117
+ query: `subscription getTransaction($transactionHash: String!) {
118
+ getTransaction(transactionHash: $transactionHash) {
119
+ receipt {
120
+ transactionHash
121
+ to
122
+ status
123
+ from
124
+ type
125
+ revertReason
126
+ revertReasonDecoded
127
+ logs
128
+ events
129
+ contractAddress
130
+ }
131
+ transactionHash
132
+ from
133
+ createdAt
134
+ address
135
+ functionName
136
+ isContract
137
+ }
138
+ }`,
139
+ variables: { transactionHash }
140
+ });
141
+ const promises = [getTransactionFromSubscription(subscription)];
142
+ if (options.timeout) {
143
+ promises.push(createTimeoutPromise(options.timeout));
144
+ }
145
+ return Promise.race(promises);
146
+ }
147
+ function createTimeoutPromise(timeout) {
148
+ return new Promise((_, reject) => {
149
+ setTimeout(() => reject(new Error("Transaction receipt not found")), timeout);
150
+ });
151
+ }
152
+ async function getTransactionFromSubscription(subscription) {
153
+ for await (const result of subscription) {
154
+ if (result?.data?.getTransaction?.receipt) {
155
+ return result.data.getTransaction;
156
+ }
157
+ }
158
+ throw new Error("No transaction found");
159
+ }
160
+
161
161
  // src/portal.ts
162
+ import { readFragment } from "gql.tada";
162
163
  var ClientOptionsSchema = z.object({
163
164
  instance: UrlOrPathSchema,
164
- accessToken: ApplicationAccessTokenSchema,
165
+ accessToken: ApplicationAccessTokenSchema.optional(),
165
166
  cache: z.enum(["default", "force-cache", "no-cache", "no-store", "only-if-cached", "reload"]).optional()
166
167
  });
167
168
  function createPortalClient(options, clientOptions) {
@@ -172,7 +173,7 @@ function createPortalClient(options, clientOptions) {
172
173
  return {
173
174
  client: new GraphQLClient(fullUrl, {
174
175
  ...clientOptions,
175
- headers: { ...clientOptions?.headers ?? {}, "x-auth-token": validatedOptions.accessToken }
176
+ headers: appendHeaders(clientOptions?.headers, { "x-auth-token": validatedOptions.accessToken })
176
177
  }),
177
178
  graphql
178
179
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/portal.ts","../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts"],"sourcesContent":["import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod/v4\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema,\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: { ...(clientOptions?.headers ?? {}), \"x-auth-token\": validatedOptions.accessToken },\n }),\n graphql,\n };\n}\n\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport {\n waitForTransactionReceipt,\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n","import { createClient } from \"graphql-ws\";\n\n/**\n * Options for the GraphQL WebSocket client\n */\nexport interface WebsocketClientOptions {\n /**\n * The GraphQL endpoint URL for the Portal API\n */\n portalGraphqlEndpoint: string;\n /**\n * The access token for authentication with the Portal API\n */\n accessToken: string;\n}\n\n/**\n * Creates a GraphQL WebSocket client for the Portal API\n *\n * @param {WebsocketClientOptions} options - The options for the client\n * @returns {Client} The GraphQL WebSocket client\n * @example\n * import { getWebsocketClient } from \"@settlemint/sdk-portal\";\n *\n * const client = getWebsocketClient({\n * portalGraphqlEndpoint: \"https://portal.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * });\n */\nexport function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions) {\n if (!portalGraphqlEndpoint) {\n throw new Error(\"portalGraphqlEndpoint is required\");\n }\n if (!accessToken) {\n throw new Error(\"accessToken is required\");\n }\n const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`,\n });\n}\n\nfunction setWsProtocol(url: URL) {\n if (url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return url;\n }\n if (url.protocol === \"http:\") {\n url.protocol = \"ws:\";\n } else {\n url.protocol = \"wss:\";\n }\n return url;\n}\n","import type { FormattedExecutionResult } from \"graphql-ws\";\nimport type { Address, Hex, TransactionReceipt as TransactionReceiptViem } from \"viem\";\nimport { type WebsocketClientOptions, getWebsocketClient } from \"./websocket-client.js\";\n\n/**\n * Represents an event emitted during a transaction execution\n *\n * @typedef {Object} TransactionEvent\n * @property {string} eventName - The name of the event that was emitted\n * @property {Record<string, unknown>} args - The arguments emitted by the event\n * @property {Hex[]} topics - Indexed event parameters used for filtering and searching\n */\n\nexport interface TransactionEvent {\n eventName: string;\n args: Record<string, unknown>;\n topics: Hex[];\n}\n\n/**\n * Represents the structure of a blockchain transaction receipt\n */\nexport interface TransactionReceipt extends TransactionReceiptViem<string, number, \"Success\" | \"Reverted\"> {\n /** The raw reason for transaction reversion, if applicable */\n revertReason: string;\n /** Human-readable version of the revert reason */\n revertReasonDecoded: string;\n /** Array of events emitted during the transaction */\n events: TransactionEvent[];\n /** The address of the contract deployed in the transaction */\n contractAddress: Address;\n}\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n */\nexport interface Transaction {\n receipt: TransactionReceipt;\n /** The hash of the transaction (duplicate of receipt.transactionHash) */\n transactionHash: string;\n /** The sender address (duplicate of receipt.from) */\n from: string;\n /** Timestamp when the transaction was created */\n createdAt: string;\n /** The contract address involved in the transaction */\n address: string;\n /** The name of the function called in the transaction */\n functionName: string;\n /** Whether the transaction is a contract deployment */\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Options for waiting for a transaction receipt\n */\nexport interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {\n /** Optional timeout in milliseconds before the operation fails */\n timeout?: number;\n}\n\n/**\n * Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.\n * This function polls until the transaction is confirmed or the timeout is reached.\n *\n * @param transactionHash - The hash of the transaction to wait for\n * @param options - Configuration options for the waiting process\n * @returns The transaction details including receipt information when the transaction is confirmed\n * @throws Error if the transaction receipt cannot be retrieved within the specified timeout\n *\n * @example\n * import { waitForTransactionReceipt } from \"@settlemint/sdk-portal\";\n *\n * const transaction = await waitForTransactionReceipt(\"0x123...\", {\n * portalGraphqlEndpoint: \"https://example.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * timeout: 30000 // 30 seconds timeout\n * });\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = getWebsocketClient(options);\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n /** The portal client instance */\n portalClient: GraphQLClient;\n /** The GraphQL query builder */\n portalGraphql: initGraphQLTada<Setup>;\n /** The ID of the verification challenge */\n verificationId: string;\n /** The wallet address to verify */\n userWalletAddress: Address;\n /** The verification code provided by the user */\n code: string | number;\n /** The type of verification being performed */\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/portal.ts","../src/utils/wallet-verification-challenge.ts","../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts"],"sourcesContent":["import { appendHeaders } from \"@settlemint/sdk-utils/http\";\nimport { ensureServer } from \"@settlemint/sdk-utils/runtime\";\nimport { ApplicationAccessTokenSchema, UrlOrPathSchema, validate } from \"@settlemint/sdk-utils/validation\";\nimport { type AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport { GraphQLClient } from \"graphql-request\";\nimport { z } from \"zod/v4\";\n\n/**\n * Configuration options for the GraphQL client, excluding 'url' and 'exchanges'.\n */\nexport type RequestConfig = ConstructorParameters<typeof GraphQLClient>[1];\n\n/**\n * Schema for validating Portal client configuration options.\n */\nexport const ClientOptionsSchema = z.object({\n instance: UrlOrPathSchema,\n accessToken: ApplicationAccessTokenSchema.optional(),\n cache: z.enum([\"default\", \"force-cache\", \"no-cache\", \"no-store\", \"only-if-cached\", \"reload\"]).optional(),\n});\n\n/**\n * Type representing the validated client options.\n */\nexport type ClientOptions = z.infer<typeof ClientOptionsSchema>;\n\n/**\n * Creates a Portal GraphQL client with the provided configuration.\n *\n * @param options - Configuration options for the Portal client\n * @param clientOptions - Additional GraphQL client configuration options\n * @returns An object containing the configured GraphQL client and graphql helper function\n * @throws If the provided options fail validation\n *\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { loadEnv } from \"@settlemint/sdk-utils/environment\";\n * import { createLogger, requestLogger } from \"@settlemint/sdk-utils/logging\";\n * import type { introspection } from \"@schemas/portal-env\";\n *\n * const env = await loadEnv(false, false);\n * const logger = createLogger();\n *\n * const { client: portalClient, graphql: portalGraphql } = createPortalClient<{\n * introspection: introspection;\n * disableMasking: true;\n * scalars: {\n * // Change unknown to the type you are using to store metadata\n * JSON: unknown;\n * };\n * }>(\n * {\n * instance: env.SETTLEMINT_PORTAL_GRAPHQL_ENDPOINT!,\n * accessToken: env.SETTLEMINT_ACCESS_TOKEN!,\n * },\n * {\n * fetch: requestLogger(logger, \"portal\", fetch) as typeof fetch,\n * },\n * );\n *\n * // Making GraphQL queries\n * const query = portalGraphql(`\n * query GetPendingTransactions {\n * getPendingTransactions {\n * count\n * }\n * }\n * `);\n *\n * const result = await portalClient.request(query);\n */\nexport function createPortalClient<const Setup extends AbstractSetupSchema>(\n options: ClientOptions,\n clientOptions?: RequestConfig,\n): {\n client: GraphQLClient;\n graphql: initGraphQLTada<Setup>;\n} {\n ensureServer();\n const validatedOptions = validate(ClientOptionsSchema, options);\n const graphql = initGraphQLTada<Setup>();\n const fullUrl = new URL(validatedOptions.instance).toString();\n\n return {\n client: new GraphQLClient(fullUrl, {\n ...clientOptions,\n headers: appendHeaders(clientOptions?.headers, { \"x-auth-token\": validatedOptions.accessToken }),\n }),\n graphql,\n };\n}\n\nexport {\n handleWalletVerificationChallenge,\n type HandleWalletVerificationChallengeOptions,\n} from \"./utils/wallet-verification-challenge.js\";\nexport {\n waitForTransactionReceipt,\n type WaitForTransactionReceiptOptions,\n type Transaction,\n type TransactionEvent,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\nexport { readFragment } from \"gql.tada\";\nexport type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\n","import { createHash } from \"node:crypto\";\nimport type { AbstractSetupSchema, initGraphQLTada } from \"gql.tada\";\nimport type { GraphQLClient } from \"graphql-request\";\nimport type { Address } from \"viem\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class ChallengeError extends Error {\n readonly code: string;\n\n constructor(message: string, code: string) {\n super(message);\n this.name = \"ChallengeError\";\n this.code = code;\n }\n}\n\n/**\n * Represents the structure of a wallet verification challenge\n */\ninterface WalletVerificationChallenge {\n challenge: {\n secret: string;\n salt: string;\n };\n id: string;\n name: string;\n verificationType: string;\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenges mutation\n */\ninterface CreateWalletVerificationChallengesResponse {\n createWalletVerificationChallenges: WalletVerificationChallenge[];\n}\n\n/**\n * Hashes a pincode with a salt using SHA-256\n * @param pincode - The pincode to hash\n * @param salt - The salt to use in hashing\n * @returns The hashed pincode as a hex string\n */\nfunction hashPincode(pincode: string, salt: string): string {\n return createHash(\"sha256\").update(`${salt}${pincode}`).digest(\"hex\");\n}\n\n/**\n * Generates a challenge response by combining a hashed pincode with a challenge\n * @param pincode - The user's pincode\n * @param salt - The salt provided in the challenge\n * @param challenge - The challenge secret\n * @returns The challenge response as a hex string\n */\nfunction generateResponse(pincode: string, salt: string, challenge: string): string {\n const hashedPincode = hashPincode(pincode, salt);\n return createHash(\"sha256\").update(`${hashedPincode}_${challenge}`).digest(\"hex\");\n}\n\n/**\n * Options for handling a wallet verification challenge\n *\n * @typedef {Object} HandleWalletVerificationChallengeOptions\n * @template {AbstractSetupSchema} Setup - The GraphQL schema setup type\n * @property {GraphQLClient} portalClient - The portal client instance\n * @property {initGraphQLTada<Setup>} portalGraphql - The GraphQL query builder\n * @property {string} verificationId - The ID of the verification challenge\n * @property {Address} userWalletAddress - The wallet address to verify\n * @property {string | number} code - The verification code provided by the user\n * @property {\"otp\" | \"secret-code\" | \"pincode\"} verificationType - The type of verification being performed\n */\nexport interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSchema> {\n portalClient: GraphQLClient;\n portalGraphql: initGraphQLTada<Setup>;\n verificationId: string;\n userWalletAddress: Address;\n code: string | number;\n verificationType: \"otp\" | \"secret-code\" | \"pincode\";\n}\n\n/**\n * Handles a wallet verification challenge by generating an appropriate response\n *\n * @param options - The options for handling the wallet verification challenge\n * @returns Promise resolving to an object containing the challenge response and optionally the verification ID\n * @throws {ChallengeError} If the challenge cannot be created or is invalid\n * @example\n * import { createPortalClient } from \"@settlemint/sdk-portal\";\n * import { handleWalletVerificationChallenge } from \"@settlemint/sdk-portal\";\n *\n * const { client, graphql } = createPortalClient({\n * instance: \"https://portal.example.com/graphql\",\n * accessToken: \"your-access-token\"\n * });\n *\n * const result = await handleWalletVerificationChallenge({\n * portalClient: client,\n * portalGraphql: graphql,\n * verificationId: \"verification-123\",\n * userWalletAddress: \"0x123...\",\n * code: \"123456\",\n * verificationType: \"otp\"\n * });\n */\nexport async function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({\n portalClient,\n portalGraphql,\n verificationId,\n userWalletAddress,\n code,\n verificationType,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n verificationId?: string;\n}> {\n try {\n if (verificationType === \"otp\") {\n return {\n challengeResponse: code.toString(),\n verificationId,\n };\n }\n\n if (verificationType === \"secret-code\") {\n // Add - separator to the code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n verificationId,\n };\n }\n\n const verificationChallenges = await portalClient.request<CreateWalletVerificationChallengesResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {\n challenge\n id\n name\n verificationType\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n );\n\n if (!verificationChallenges.createWalletVerificationChallenges?.length) {\n throw new ChallengeError(\"No verification challenges received\", \"NO_CHALLENGES\");\n }\n\n const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find(\n (challenge) => challenge.id === verificationId,\n );\n\n if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {\n throw new ChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const { secret, salt } = walletVerificationChallenge.challenge;\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n verificationId,\n };\n } catch (error) {\n if (error instanceof ChallengeError) {\n throw error;\n }\n throw new ChallengeError(\"Failed to process wallet verification challenge\", \"CHALLENGE_PROCESSING_ERROR\");\n }\n}\n","import { createClient } from \"graphql-ws\";\n\n/**\n * Options for the GraphQL WebSocket client\n *\n * @typedef {Object} WebsocketClientOptions\n * @property {string} portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @property {string} accessToken - The access token for authentication with the Portal API\n */\nexport interface WebsocketClientOptions {\n portalGraphqlEndpoint: string;\n accessToken: string;\n}\n\n/**\n * Creates a GraphQL WebSocket client for the Portal API\n *\n * @param {WebsocketClientOptions} options - The options for the client\n * @param {string} options.portalGraphqlEndpoint - The GraphQL endpoint URL for the Portal API\n * @param {string} options.accessToken - The access token for authentication with the Portal API\n * @returns {Client} The GraphQL WebSocket client\n */\nexport function getWebsocketClient({ portalGraphqlEndpoint, accessToken }: WebsocketClientOptions) {\n if (!portalGraphqlEndpoint) {\n throw new Error(\"portalGraphqlEndpoint is required\");\n }\n if (!accessToken) {\n throw new Error(\"accessToken is required\");\n }\n const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`,\n });\n}\n\nfunction setWsProtocol(url: URL) {\n if (url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return url;\n }\n if (url.protocol === \"http:\") {\n url.protocol = \"ws:\";\n } else {\n url.protocol = \"wss:\";\n }\n return url;\n}\n","import type { FormattedExecutionResult } from \"graphql-ws\";\nimport { type WebsocketClientOptions, getWebsocketClient } from \"./websocket-client.js\";\n\nimport type { Hex, TransactionReceipt } from \"viem\";\n\n/**\n * Represents an event emitted during a transaction execution\n *\n * @typedef {Object} TransactionEvent\n * @property {string} eventName - The name of the event that was emitted\n * @property {Record<string, unknown>} args - The arguments emitted by the event\n * @property {Hex[]} topics - Indexed event parameters used for filtering and searching\n */\n\nexport interface TransactionEvent {\n eventName: string;\n args: Record<string, unknown>;\n topics: Hex[];\n}\n\n/**\n * Represents the structure of a blockchain transaction with its receipt\n *\n * @typedef {Object} Transaction\n * @property {Object} receipt - The transaction receipt details\n * @property {string} receipt.transactionHash - The hash of the transaction\n * @property {string} receipt.to - The recipient address of the transaction\n * @property {string} receipt.status - The status of the transaction (success/failure)\n * @property {string} receipt.from - The sender address of the transaction\n * @property {string} receipt.type - The type of the transaction\n * @property {string} receipt.revertReason - The reason for transaction reversion, if applicable\n * @property {string} receipt.revertReasonDecoded - Human-readable version of the revert reason\n * @property {string} receipt.contractAddress - The address of the contract deployed in the transaction\n * @property {string[]} receipt.logs - Array of log entries generated by the transaction\n * @property {TransactionEvent[]} receipt.events - Array of events emitted during the transaction\n * @property {string} transactionHash - The hash of the transaction (duplicate of receipt.transactionHash)\n * @property {string} from - The sender address (duplicate of receipt.from)\n * @property {string} createdAt - Timestamp when the transaction was created\n * @property {string} address - The contract address involved in the transaction\n * @property {string} functionName - The name of the function called in the transaction\n * @property {boolean} isContract - Whether the transaction is a contract deployment\n */\nexport interface Transaction {\n receipt: TransactionReceipt<string, number, \"Success\" | \"Reverted\"> & {\n revertReason: string;\n revertReasonDecoded: string;\n events: TransactionEvent[];\n contractAddress: string;\n };\n transactionHash: string;\n from: string;\n createdAt: string;\n address: string;\n functionName: string;\n isContract: boolean;\n}\n\ninterface GetTransactionResponse {\n getTransaction: Transaction;\n}\n\n/**\n * Options for waiting for a transaction receipt\n *\n * @typedef {Object} WaitForTransactionReceiptOptions\n * @property {number} [timeout] - Optional timeout in milliseconds before the operation fails\n */\nexport interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {\n timeout?: number;\n}\n\n/**\n * Waits for a blockchain transaction receipt by subscribing to transaction updates via GraphQL.\n * This function polls until the transaction is confirmed or the timeout is reached.\n *\n * @param transactionHash - The hash of the transaction to wait for\n * @param options - Configuration options for the waiting process\n * @returns The transaction details including receipt information when the transaction is confirmed\n * @throws Error if the transaction receipt cannot be retrieved within the specified timeout\n *\n * @example\n * import { waitForTransactionReceipt } from \"@settlemint/sdk-portal\";\n *\n * const transaction = await waitForTransactionReceipt(\"0x123...\", {\n * portalGraphqlEndpoint: \"https://example.settlemint.com/graphql\",\n * accessToken: \"your-access-token\",\n * timeout: 30000 // 30 seconds timeout\n * });\n */\nexport async function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions) {\n const wsClient = getWebsocketClient(options);\n const subscription = wsClient.iterate<GetTransactionResponse>({\n query: `subscription getTransaction($transactionHash: String!) {\n getTransaction(transactionHash: $transactionHash) {\n receipt {\n transactionHash\n to\n status\n from\n type\n revertReason\n revertReasonDecoded\n logs\n events\n contractAddress\n }\n transactionHash\n from\n createdAt\n address\n functionName\n isContract\n }\n }`,\n variables: { transactionHash },\n });\n const promises = [getTransactionFromSubscription(subscription)];\n if (options.timeout) {\n promises.push(createTimeoutPromise(options.timeout));\n }\n\n return Promise.race(promises);\n}\n\nfunction createTimeoutPromise(timeout: number): Promise<never> {\n return new Promise((_, reject) => {\n setTimeout(() => reject(new Error(\"Transaction receipt not found\")), timeout);\n });\n}\n\nasync function getTransactionFromSubscription(\n subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>,\n): Promise<Transaction> {\n for await (const result of subscription) {\n if (result?.data?.getTransaction?.receipt) {\n return result.data.getTransaction;\n }\n }\n throw new Error(\"No transaction found\");\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@settlemint/sdk-portal",
3
3
  "description": "Portal API client module for SettleMint SDK, providing access to smart contract portal services and APIs",
4
- "version": "2.3.2-pr8d084a79",
4
+ "version": "2.3.2-pr8d2ec5b5",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "FSL-1.1-MIT",
@@ -56,7 +56,7 @@
56
56
  "dependencies": {
57
57
  "gql.tada": "^1",
58
58
  "graphql-ws": "^6",
59
- "@settlemint/sdk-utils": "2.3.2-pr8d084a79",
59
+ "@settlemint/sdk-utils": "2.3.2-pr8d2ec5b5",
60
60
  "graphql-request": "^7",
61
61
  "zod": "^3.25.0"
62
62
  },