@settlemint/sdk-portal 2.5.14-pr4da67ef3 → 2.5.14-pr9a38dbdb

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.
@@ -108,14 +108,10 @@ interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
108
108
  declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
109
109
  //#endregion
110
110
  //#region src/utils/wallet-verification-challenge.d.ts
111
- /**
112
- * Type representing the different types of wallet verification methods
113
- */
114
- type WalletVerificationType = "PINCODE" | "OTP" | "SECRET_CODES";
115
111
  /**
116
112
  * Custom error class for challenge-related errors
117
113
  */
118
- declare class WalletVerificationChallengeError extends Error {
114
+ declare class ChallengeError extends Error {
119
115
  readonly code: string;
120
116
  constructor(message: string, code: string);
121
117
  }
@@ -134,16 +130,14 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
134
130
  /** The verification code provided by the user */
135
131
  code: string | number;
136
132
  /** The type of verification being performed */
137
- verificationType: WalletVerificationType;
138
- /** Request id which can be added for tracing purposes */
139
- requestId?: string;
133
+ verificationType: "otp" | "secret-code" | "pincode";
140
134
  }
141
135
  /**
142
136
  * Handles a wallet verification challenge by generating an appropriate response
143
137
  *
144
138
  * @param options - The options for handling the wallet verification challenge
145
139
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
146
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
140
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
147
141
  * @example
148
142
  * import { createPortalClient } from "@settlemint/sdk-portal";
149
143
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -159,7 +153,7 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
159
153
  * verificationId: "verification-123",
160
154
  * userWalletAddress: "0x123...",
161
155
  * code: "123456",
162
- * verificationType: "OTP"
156
+ * verificationType: "otp"
163
157
  * });
164
158
  */
165
159
  declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({
@@ -168,11 +162,10 @@ declare function handleWalletVerificationChallenge<const Setup extends AbstractS
168
162
  verificationId,
169
163
  userWalletAddress,
170
164
  code,
171
- verificationType,
172
- requestId
165
+ verificationType
173
166
  }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
174
167
  challengeResponse: string;
175
- challengeId: string;
168
+ verificationId?: string;
176
169
  }>;
177
170
  //#endregion
178
171
  //#region src/portal.d.ts
@@ -249,5 +242,5 @@ declare function createPortalClient<const Setup extends AbstractSetupSchema>(opt
249
242
  graphql: initGraphQLTada<Setup>;
250
243
  };
251
244
  //#endregion
252
- export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, WalletVerificationChallengeError, type WalletVerificationType, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
245
+ export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
253
246
  //# sourceMappingURL=portal.d.ts.map
@@ -113,7 +113,7 @@ async function getTransactionFromSubscription(subscription) {
113
113
  /**
114
114
  * Custom error class for challenge-related errors
115
115
  */
116
- var WalletVerificationChallengeError = class extends Error {
116
+ var ChallengeError = class extends Error {
117
117
  code;
118
118
  constructor(message, code) {
119
119
  super(message);
@@ -146,7 +146,7 @@ function generateResponse(pincode, salt, challenge) {
146
146
  *
147
147
  * @param options - The options for handling the wallet verification challenge
148
148
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
149
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
149
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
150
150
  * @example
151
151
  * import { createPortalClient } from "@settlemint/sdk-portal";
152
152
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -162,65 +162,55 @@ function generateResponse(pincode, salt, challenge) {
162
162
  * verificationId: "verification-123",
163
163
  * userWalletAddress: "0x123...",
164
164
  * code: "123456",
165
- * verificationType: "OTP"
165
+ * verificationType: "otp"
166
166
  * });
167
167
  */
168
- async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, requestId }) {
168
+ async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType }) {
169
169
  try {
170
- const requestHeaders = new Headers();
171
- if (requestId) {
172
- requestHeaders.append("x-request-id", requestId);
170
+ if (verificationType === "otp") {
171
+ return {
172
+ challengeResponse: code.toString(),
173
+ verificationId
174
+ };
173
175
  }
174
- const verificationChallenge = await portalClient.request(portalGraphql(`
175
- mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {
176
- createWalletVerificationChallenge(
177
- userWalletAddress: $userWalletAddress
178
- verificationId: $verificationId
179
- ) {
176
+ if (verificationType === "secret-code") {
177
+ const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
178
+ return {
179
+ challengeResponse: formattedCode,
180
+ verificationId
181
+ };
182
+ }
183
+ const verificationChallenges = await portalClient.request(portalGraphql(`
184
+ mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {
185
+ createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {
186
+ challenge
180
187
  id
181
188
  name
182
- verificationId
183
189
  verificationType
184
- challenge {
185
- salt
186
- secret
187
- }
188
190
  }
189
191
  }
190
192
  `), {
191
193
  userWalletAddress,
192
194
  verificationId
193
- }, requestHeaders);
194
- if (!verificationChallenge.createWalletVerificationChallenge) {
195
- throw new WalletVerificationChallengeError("No verification challenge received", "NO_CHALLENGES");
196
- }
197
- if (verificationType === "OTP") {
198
- return {
199
- challengeResponse: code.toString(),
200
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
201
- };
195
+ });
196
+ if (!verificationChallenges.createWalletVerificationChallenges?.length) {
197
+ throw new ChallengeError("No verification challenges received", "NO_CHALLENGES");
202
198
  }
203
- if (verificationType === "SECRET_CODES") {
204
- const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
205
- return {
206
- challengeResponse: formattedCode,
207
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
208
- };
209
- }
210
- const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};
211
- if (!secret || !salt) {
212
- throw new WalletVerificationChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
199
+ const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find((challenge) => challenge.id === verificationId);
200
+ if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {
201
+ throw new ChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
213
202
  }
203
+ const { secret, salt } = walletVerificationChallenge.challenge;
214
204
  const challengeResponse = generateResponse(code.toString(), salt, secret);
215
205
  return {
216
206
  challengeResponse,
217
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
207
+ verificationId
218
208
  };
219
209
  } catch (error) {
220
- if (error instanceof WalletVerificationChallengeError) {
210
+ if (error instanceof ChallengeError) {
221
211
  throw error;
222
212
  }
223
- throw new WalletVerificationChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
213
+ throw new ChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
224
214
  }
225
215
  }
226
216
 
@@ -301,5 +291,5 @@ function createPortalClient(options, clientOptions) {
301
291
  }
302
292
 
303
293
  //#endregion
304
- export { ClientOptionsSchema, WalletVerificationChallengeError, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
294
+ export { ClientOptionsSchema, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
305
295
  //# sourceMappingURL=portal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"portal.js","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","options: ClientOptions","clientOptions?: RequestConfig"],"sources":["../../src/utils/websocket-client.ts","../../src/utils/wait-for-transaction-receipt.ts","../../src/utils/wallet-verification-challenge.ts","../../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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 * Type representing the different types of wallet verification methods\n */\nexport type WalletVerificationType = \"PINCODE\" | \"OTP\" | \"SECRET_CODES\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class WalletVerificationChallengeError 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 id: string;\n name: string;\n verificationId: string;\n verificationType: WalletVerificationType;\n challenge?: {\n salt: string;\n secret: string;\n };\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenge mutation\n */\ninterface CreateWalletVerificationChallengeResponse {\n createWalletVerificationChallenge: 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: WalletVerificationType;\n /** Request id which can be added for tracing purposes */\n requestId?: string;\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 {WalletVerificationChallengeError} 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 requestId,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n challengeId: string;\n}> {\n try {\n const requestHeaders = new Headers();\n if (requestId) {\n requestHeaders.append(\"x-request-id\", requestId);\n }\n const verificationChallenge = await portalClient.request<CreateWalletVerificationChallengeResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenge(\n userWalletAddress: $userWalletAddress\n verificationId: $verificationId\n ) {\n id\n name\n verificationId\n verificationType\n challenge {\n salt\n secret\n }\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n requestHeaders,\n );\n\n if (!verificationChallenge.createWalletVerificationChallenge) {\n throw new WalletVerificationChallengeError(\"No verification challenge received\", \"NO_CHALLENGES\");\n }\n\n if (verificationType === \"OTP\") {\n return {\n challengeResponse: code.toString(),\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n if (verificationType === \"SECRET_CODES\") {\n // Add a hyphen after every 5 characters to format the secret code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};\n\n if (!secret || !salt) {\n throw new WalletVerificationChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n } catch (error) {\n if (error instanceof WalletVerificationChallengeError) {\n throw error;\n }\n throw new WalletVerificationChallengeError(\n \"Failed to process wallet verification challenge\",\n \"CHALLENGE_PROCESSING_ERROR\",\n );\n }\n}\n","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n WalletVerificationChallengeError,\n type WalletVerificationType,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"portal.js","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","options: ClientOptions","clientOptions?: RequestConfig"],"sources":["../../src/utils/websocket-client.ts","../../src/utils/wait-for-transaction-receipt.ts","../../src/utils/wallet-verification-challenge.ts","../../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6BA,SAAgB,mBAAmB,EAAE,uBAAuB,aAAqC,EAAE;AACjG,KAAI,CAAC,uBAAuB;AAC1B,QAAM,IAAI,MAAM;CACjB;CACD,MAAM,kBAAkB,cAAc,IAAI,IAAI,uBAAuB;AACrE,QAAO,aAAa,EAClB,KAAK,cACD,GAAG,gBAAgB,SAAS,EAAE,EAAE,gBAAgB,KAAK,CAAC,EAAE,cAAc,gBAAgB,WAAW,gBAAgB,QAAQ,GACzH,gBAAgB,UAAU,CAC/B,EAAC;AACH;AAED,SAAS,cAAcA,KAAU;AAC/B,KAAI,IAAI,aAAa,SAAS,IAAI,aAAa,QAAQ;AACrD,SAAO;CACR;AACD,KAAI,IAAI,aAAa,SAAS;EAC5B,IAAI,WAAW;CAChB,OAAM;EACL,IAAI,WAAW;CAChB;AACD,QAAO;AACR;;;;;;;;;;;;;;;;;;;;;;AC4BD,eAAsB,0BAA0BC,iBAAyBC,SAA2C;CAClH,MAAM,WAAW,mBAAmB,QAAQ;CAC5C,MAAM,eAAe,SAAS,QAAgC;EAC5D,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;OAqBL,CAAC;EACJ,WAAW,EAAE,gBAAiB;CAC/B,EAAC;CACF,MAAM,WAAW,CAAC,+BAA+B,aAAa,AAAC;AAC/D,KAAI,QAAQ,SAAS;EACnB,SAAS,KAAK,qBAAqB,QAAQ,QAAQ,CAAC;CACrD;AAED,QAAO,QAAQ,KAAK,SAAS;AAC9B;AAED,SAAS,qBAAqBC,SAAiC;AAC7D,QAAO,IAAI,QAAQ,CAAC,GAAG,WAAW;EAChC,WAAW,MAAM,OAAO,IAAI,MAAM,iCAAiC,EAAE,QAAQ;CAC9E;AACF;AAED,eAAe,+BACbC,cACsB;AACtB,YAAW,MAAM,UAAU,cAAc;AACvC,MAAI,QAAQ,MAAM,gBAAgB,SAAS;AACzC,UAAO,OAAO,KAAK;EACpB;CACF;AACD,OAAM,IAAI,MAAM;AACjB;;;;;;;ACzHD,IAAa,iBAAb,cAAoC,MAAM;CACxC,AAAS;CAET,YAAYC,SAAiBC,MAAc;EACzC,MAAM,QAAQ;EACd,KAAK,OAAO;EACZ,KAAK,OAAO;CACb;AACF;;;;;;;AA4BD,SAAS,YAAYC,SAAiBC,MAAsB;AAC1D,QAAO,WAAW,SAAS,CAAC,OAAO,GAAG,OAAO,SAAS,CAAC,CAAC,OAAO,MAAM;AACtE;;;;;;;;AASD,SAAS,iBAAiBD,SAAiBC,MAAcC,WAA2B;CAClF,MAAM,gBAAgB,YAAY,SAAS,KAAK;AAChD,QAAO,WAAW,SAAS,CAAC,OAAO,GAAG,cAAc,CAAC,EAAE,WAAW,CAAC,CAAC,OAAO,MAAM;AAClF;;;;;;;;;;;;;;;;;;;;;;;;;AA4CD,eAAsB,kCAA2E,EAC/F,cACA,eACA,gBACA,mBACA,MACA,kBACgD,EAG/C;AACD,KAAI;AACF,MAAI,qBAAqB,OAAO;AAC9B,UAAO;IACL,mBAAmB,KAAK,UAAU;IAClC;GACD;EACF;AAED,MAAI,qBAAqB,eAAe;GAEtC,MAAM,gBAAgB,KAAK,UAAU,CAAC,QAAQ,eAAe,MAAM;AACnE,UAAO;IACL,mBAAmB;IACnB;GACD;EACF;EAED,MAAM,yBAAyB,MAAM,aAAa,QAChD,cAAc,CAAC;;;;;;;;;MASf,CAAC,CAAC,EACF;GACE;GACA;EACD,EACF;AAED,MAAI,CAAC,uBAAuB,oCAAoC,QAAQ;AACtE,SAAM,IAAI,eAAe,uCAAuC;EACjE;EAED,MAAM,8BAA8B,uBAAuB,mCAAmC,KAC5F,CAAC,cAAc,UAAU,OAAO,eACjC;AAED,MAAI,CAAC,6BAA6B,WAAW,UAAU,CAAC,6BAA6B,WAAW,MAAM;AACpG,SAAM,IAAI,eAAe,4BAA4B;EACtD;EAED,MAAM,EAAE,QAAQ,MAAM,GAAG,4BAA4B;EACrD,MAAM,oBAAoB,iBAAiB,KAAK,UAAU,EAAE,MAAM,OAAO;AACzE,SAAO;GACL;GACA;EACD;CACF,SAAQ,OAAO;AACd,MAAI,iBAAiB,gBAAgB;AACnC,SAAM;EACP;AACD,QAAM,IAAI,eAAe,mDAAmD;CAC7E;AACF;;;;;;;AC5JD,MAAa,sBAAsB,EAAE,OAAO;CAC1C,UAAU;CACV,aAAa,6BAA6B,UAAU;CACpD,OAAO,EAAE,KAAK;EAAC;EAAW;EAAe;EAAY;EAAY;EAAkB;CAAS,EAAC,CAAC,UAAU;AACzG,EAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDF,SAAgB,mBACdC,SACAC,eAIA;CACA,cAAc;CACd,MAAM,mBAAmB,SAAS,qBAAqB,QAAQ;CAC/D,MAAM,UAAU,iBAAwB;CACxC,MAAM,UAAU,IAAI,IAAI,iBAAiB,UAAU,UAAU;AAE7D,QAAO;EACL,QAAQ,IAAI,cAAc,SAAS;GACjC,GAAG;GACH,SAAS,cAAc,eAAe,SAAS,EAAE,gBAAgB,iBAAiB,YAAa,EAAC;EACjG;EACD;CACD;AACF"}
package/dist/portal.cjs CHANGED
@@ -136,7 +136,7 @@ async function getTransactionFromSubscription(subscription) {
136
136
  /**
137
137
  * Custom error class for challenge-related errors
138
138
  */
139
- var WalletVerificationChallengeError = class extends Error {
139
+ var ChallengeError = class extends Error {
140
140
  code;
141
141
  constructor(message, code) {
142
142
  super(message);
@@ -169,7 +169,7 @@ function generateResponse(pincode, salt, challenge) {
169
169
  *
170
170
  * @param options - The options for handling the wallet verification challenge
171
171
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
172
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
172
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
173
173
  * @example
174
174
  * import { createPortalClient } from "@settlemint/sdk-portal";
175
175
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -185,65 +185,55 @@ function generateResponse(pincode, salt, challenge) {
185
185
  * verificationId: "verification-123",
186
186
  * userWalletAddress: "0x123...",
187
187
  * code: "123456",
188
- * verificationType: "OTP"
188
+ * verificationType: "otp"
189
189
  * });
190
190
  */
191
- async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, requestId }) {
191
+ async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType }) {
192
192
  try {
193
- const requestHeaders = new Headers();
194
- if (requestId) {
195
- requestHeaders.append("x-request-id", requestId);
193
+ if (verificationType === "otp") {
194
+ return {
195
+ challengeResponse: code.toString(),
196
+ verificationId
197
+ };
198
+ }
199
+ if (verificationType === "secret-code") {
200
+ const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
201
+ return {
202
+ challengeResponse: formattedCode,
203
+ verificationId
204
+ };
196
205
  }
197
- const verificationChallenge = await portalClient.request(portalGraphql(`
198
- mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {
199
- createWalletVerificationChallenge(
200
- userWalletAddress: $userWalletAddress
201
- verificationId: $verificationId
202
- ) {
206
+ const verificationChallenges = await portalClient.request(portalGraphql(`
207
+ mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {
208
+ createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {
209
+ challenge
203
210
  id
204
211
  name
205
- verificationId
206
212
  verificationType
207
- challenge {
208
- salt
209
- secret
210
- }
211
213
  }
212
214
  }
213
215
  `), {
214
216
  userWalletAddress,
215
217
  verificationId
216
- }, requestHeaders);
217
- if (!verificationChallenge.createWalletVerificationChallenge) {
218
- throw new WalletVerificationChallengeError("No verification challenge received", "NO_CHALLENGES");
219
- }
220
- if (verificationType === "OTP") {
221
- return {
222
- challengeResponse: code.toString(),
223
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
224
- };
225
- }
226
- if (verificationType === "SECRET_CODES") {
227
- const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
228
- return {
229
- challengeResponse: formattedCode,
230
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
231
- };
218
+ });
219
+ if (!verificationChallenges.createWalletVerificationChallenges?.length) {
220
+ throw new ChallengeError("No verification challenges received", "NO_CHALLENGES");
232
221
  }
233
- const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};
234
- if (!secret || !salt) {
235
- throw new WalletVerificationChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
222
+ const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find((challenge) => challenge.id === verificationId);
223
+ if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {
224
+ throw new ChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
236
225
  }
226
+ const { secret, salt } = walletVerificationChallenge.challenge;
237
227
  const challengeResponse = generateResponse(code.toString(), salt, secret);
238
228
  return {
239
229
  challengeResponse,
240
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
230
+ verificationId
241
231
  };
242
232
  } catch (error) {
243
- if (error instanceof WalletVerificationChallengeError) {
233
+ if (error instanceof ChallengeError) {
244
234
  throw error;
245
235
  }
246
- throw new WalletVerificationChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
236
+ throw new ChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
247
237
  }
248
238
  }
249
239
 
@@ -325,7 +315,6 @@ function createPortalClient(options, clientOptions) {
325
315
 
326
316
  //#endregion
327
317
  exports.ClientOptionsSchema = ClientOptionsSchema;
328
- exports.WalletVerificationChallengeError = WalletVerificationChallengeError;
329
318
  exports.createPortalClient = createPortalClient;
330
319
  exports.getWebsocketClient = getWebsocketClient;
331
320
  exports.handleWalletVerificationChallenge = handleWalletVerificationChallenge;
@@ -1 +1 @@
1
- {"version":3,"file":"portal.cjs","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","z","UrlOrPathSchema","ApplicationAccessTokenSchema","options: ClientOptions","clientOptions?: RequestConfig","GraphQLClient"],"sources":["../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts","../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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 * Type representing the different types of wallet verification methods\n */\nexport type WalletVerificationType = \"PINCODE\" | \"OTP\" | \"SECRET_CODES\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class WalletVerificationChallengeError 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 id: string;\n name: string;\n verificationId: string;\n verificationType: WalletVerificationType;\n challenge?: {\n salt: string;\n secret: string;\n };\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenge mutation\n */\ninterface CreateWalletVerificationChallengeResponse {\n createWalletVerificationChallenge: 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: WalletVerificationType;\n /** Request id which can be added for tracing purposes */\n requestId?: string;\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 {WalletVerificationChallengeError} 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 requestId,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n challengeId: string;\n}> {\n try {\n const requestHeaders = new Headers();\n if (requestId) {\n requestHeaders.append(\"x-request-id\", requestId);\n }\n const verificationChallenge = await portalClient.request<CreateWalletVerificationChallengeResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenge(\n userWalletAddress: $userWalletAddress\n verificationId: $verificationId\n ) {\n id\n name\n verificationId\n verificationType\n challenge {\n salt\n secret\n }\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n requestHeaders,\n );\n\n if (!verificationChallenge.createWalletVerificationChallenge) {\n throw new WalletVerificationChallengeError(\"No verification challenge received\", \"NO_CHALLENGES\");\n }\n\n if (verificationType === \"OTP\") {\n return {\n challengeResponse: code.toString(),\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n if (verificationType === \"SECRET_CODES\") {\n // Add a hyphen after every 5 characters to format the secret code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};\n\n if (!secret || !salt) {\n throw new WalletVerificationChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n } catch (error) {\n if (error instanceof WalletVerificationChallengeError) {\n throw error;\n }\n throw new WalletVerificationChallengeError(\n \"Failed to process wallet verification challenge\",\n \"CHALLENGE_PROCESSING_ERROR\",\n );\n }\n}\n","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n WalletVerificationChallengeError,\n type WalletVerificationType,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"portal.cjs","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","z","UrlOrPathSchema","ApplicationAccessTokenSchema","options: ClientOptions","clientOptions?: RequestConfig","GraphQLClient"],"sources":["../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts","../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":"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"}
package/dist/portal.d.cts CHANGED
@@ -108,14 +108,10 @@ interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
108
108
  declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
109
109
  //#endregion
110
110
  //#region src/utils/wallet-verification-challenge.d.ts
111
- /**
112
- * Type representing the different types of wallet verification methods
113
- */
114
- type WalletVerificationType = "PINCODE" | "OTP" | "SECRET_CODES";
115
111
  /**
116
112
  * Custom error class for challenge-related errors
117
113
  */
118
- declare class WalletVerificationChallengeError extends Error {
114
+ declare class ChallengeError extends Error {
119
115
  readonly code: string;
120
116
  constructor(message: string, code: string);
121
117
  }
@@ -134,16 +130,14 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
134
130
  /** The verification code provided by the user */
135
131
  code: string | number;
136
132
  /** The type of verification being performed */
137
- verificationType: WalletVerificationType;
138
- /** Request id which can be added for tracing purposes */
139
- requestId?: string;
133
+ verificationType: "otp" | "secret-code" | "pincode";
140
134
  }
141
135
  /**
142
136
  * Handles a wallet verification challenge by generating an appropriate response
143
137
  *
144
138
  * @param options - The options for handling the wallet verification challenge
145
139
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
146
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
140
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
147
141
  * @example
148
142
  * import { createPortalClient } from "@settlemint/sdk-portal";
149
143
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -159,7 +153,7 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
159
153
  * verificationId: "verification-123",
160
154
  * userWalletAddress: "0x123...",
161
155
  * code: "123456",
162
- * verificationType: "OTP"
156
+ * verificationType: "otp"
163
157
  * });
164
158
  */
165
159
  declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({
@@ -168,11 +162,10 @@ declare function handleWalletVerificationChallenge<const Setup extends AbstractS
168
162
  verificationId,
169
163
  userWalletAddress,
170
164
  code,
171
- verificationType,
172
- requestId
165
+ verificationType
173
166
  }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
174
167
  challengeResponse: string;
175
- challengeId: string;
168
+ verificationId?: string;
176
169
  }>;
177
170
  //#endregion
178
171
  //#region src/portal.d.ts
@@ -249,5 +242,5 @@ declare function createPortalClient<const Setup extends AbstractSetupSchema>(opt
249
242
  graphql: initGraphQLTada<Setup>;
250
243
  };
251
244
  //#endregion
252
- export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, WalletVerificationChallengeError, type WalletVerificationType, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
245
+ export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
253
246
  //# sourceMappingURL=portal.d.cts.map
package/dist/portal.d.ts CHANGED
@@ -108,14 +108,10 @@ interface WaitForTransactionReceiptOptions extends WebsocketClientOptions {
108
108
  declare function waitForTransactionReceipt(transactionHash: string, options: WaitForTransactionReceiptOptions): Promise<Transaction>;
109
109
  //#endregion
110
110
  //#region src/utils/wallet-verification-challenge.d.ts
111
- /**
112
- * Type representing the different types of wallet verification methods
113
- */
114
- type WalletVerificationType = "PINCODE" | "OTP" | "SECRET_CODES";
115
111
  /**
116
112
  * Custom error class for challenge-related errors
117
113
  */
118
- declare class WalletVerificationChallengeError extends Error {
114
+ declare class ChallengeError extends Error {
119
115
  readonly code: string;
120
116
  constructor(message: string, code: string);
121
117
  }
@@ -134,16 +130,14 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
134
130
  /** The verification code provided by the user */
135
131
  code: string | number;
136
132
  /** The type of verification being performed */
137
- verificationType: WalletVerificationType;
138
- /** Request id which can be added for tracing purposes */
139
- requestId?: string;
133
+ verificationType: "otp" | "secret-code" | "pincode";
140
134
  }
141
135
  /**
142
136
  * Handles a wallet verification challenge by generating an appropriate response
143
137
  *
144
138
  * @param options - The options for handling the wallet verification challenge
145
139
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
146
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
140
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
147
141
  * @example
148
142
  * import { createPortalClient } from "@settlemint/sdk-portal";
149
143
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -159,7 +153,7 @@ interface HandleWalletVerificationChallengeOptions<Setup extends AbstractSetupSc
159
153
  * verificationId: "verification-123",
160
154
  * userWalletAddress: "0x123...",
161
155
  * code: "123456",
162
- * verificationType: "OTP"
156
+ * verificationType: "otp"
163
157
  * });
164
158
  */
165
159
  declare function handleWalletVerificationChallenge<const Setup extends AbstractSetupSchema>({
@@ -168,11 +162,10 @@ declare function handleWalletVerificationChallenge<const Setup extends AbstractS
168
162
  verificationId,
169
163
  userWalletAddress,
170
164
  code,
171
- verificationType,
172
- requestId
165
+ verificationType
173
166
  }: HandleWalletVerificationChallengeOptions<Setup>): Promise<{
174
167
  challengeResponse: string;
175
- challengeId: string;
168
+ verificationId?: string;
176
169
  }>;
177
170
  //#endregion
178
171
  //#region src/portal.d.ts
@@ -249,5 +242,5 @@ declare function createPortalClient<const Setup extends AbstractSetupSchema>(opt
249
242
  graphql: initGraphQLTada<Setup>;
250
243
  };
251
244
  //#endregion
252
- export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, WalletVerificationChallengeError, type WalletVerificationType, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
245
+ export { ClientOptions, ClientOptionsSchema, type FragmentOf, type HandleWalletVerificationChallengeOptions, RequestConfig, type ResultOf, type Transaction, type TransactionEvent, type TransactionReceipt, type VariablesOf, type WaitForTransactionReceiptOptions, type WebsocketClientOptions, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
253
246
  //# sourceMappingURL=portal.d.ts.map
package/dist/portal.js CHANGED
@@ -113,7 +113,7 @@ async function getTransactionFromSubscription(subscription) {
113
113
  /**
114
114
  * Custom error class for challenge-related errors
115
115
  */
116
- var WalletVerificationChallengeError = class extends Error {
116
+ var ChallengeError = class extends Error {
117
117
  code;
118
118
  constructor(message, code) {
119
119
  super(message);
@@ -146,7 +146,7 @@ function generateResponse(pincode, salt, challenge) {
146
146
  *
147
147
  * @param options - The options for handling the wallet verification challenge
148
148
  * @returns Promise resolving to an object containing the challenge response and optionally the verification ID
149
- * @throws {WalletVerificationChallengeError} If the challenge cannot be created or is invalid
149
+ * @throws {ChallengeError} If the challenge cannot be created or is invalid
150
150
  * @example
151
151
  * import { createPortalClient } from "@settlemint/sdk-portal";
152
152
  * import { handleWalletVerificationChallenge } from "@settlemint/sdk-portal";
@@ -162,65 +162,55 @@ function generateResponse(pincode, salt, challenge) {
162
162
  * verificationId: "verification-123",
163
163
  * userWalletAddress: "0x123...",
164
164
  * code: "123456",
165
- * verificationType: "OTP"
165
+ * verificationType: "otp"
166
166
  * });
167
167
  */
168
- async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType, requestId }) {
168
+ async function handleWalletVerificationChallenge({ portalClient, portalGraphql, verificationId, userWalletAddress, code, verificationType }) {
169
169
  try {
170
- const requestHeaders = new Headers();
171
- if (requestId) {
172
- requestHeaders.append("x-request-id", requestId);
170
+ if (verificationType === "otp") {
171
+ return {
172
+ challengeResponse: code.toString(),
173
+ verificationId
174
+ };
173
175
  }
174
- const verificationChallenge = await portalClient.request(portalGraphql(`
175
- mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {
176
- createWalletVerificationChallenge(
177
- userWalletAddress: $userWalletAddress
178
- verificationId: $verificationId
179
- ) {
176
+ if (verificationType === "secret-code") {
177
+ const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
178
+ return {
179
+ challengeResponse: formattedCode,
180
+ verificationId
181
+ };
182
+ }
183
+ const verificationChallenges = await portalClient.request(portalGraphql(`
184
+ mutation CreateWalletVerificationChallenges($userWalletAddress: String!, $verificationId: String!) {
185
+ createWalletVerificationChallenges(userWalletAddress: $userWalletAddress, verificationId: $verificationId) {
186
+ challenge
180
187
  id
181
188
  name
182
- verificationId
183
189
  verificationType
184
- challenge {
185
- salt
186
- secret
187
- }
188
190
  }
189
191
  }
190
192
  `), {
191
193
  userWalletAddress,
192
194
  verificationId
193
- }, requestHeaders);
194
- if (!verificationChallenge.createWalletVerificationChallenge) {
195
- throw new WalletVerificationChallengeError("No verification challenge received", "NO_CHALLENGES");
196
- }
197
- if (verificationType === "OTP") {
198
- return {
199
- challengeResponse: code.toString(),
200
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
201
- };
195
+ });
196
+ if (!verificationChallenges.createWalletVerificationChallenges?.length) {
197
+ throw new ChallengeError("No verification challenges received", "NO_CHALLENGES");
202
198
  }
203
- if (verificationType === "SECRET_CODES") {
204
- const formattedCode = code.toString().replace(/(.{5})(?=.)/, "$1-");
205
- return {
206
- challengeResponse: formattedCode,
207
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
208
- };
209
- }
210
- const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};
211
- if (!secret || !salt) {
212
- throw new WalletVerificationChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
199
+ const walletVerificationChallenge = verificationChallenges.createWalletVerificationChallenges.find((challenge) => challenge.id === verificationId);
200
+ if (!walletVerificationChallenge?.challenge?.secret || !walletVerificationChallenge?.challenge?.salt) {
201
+ throw new ChallengeError("Invalid challenge format", "INVALID_CHALLENGE");
213
202
  }
203
+ const { secret, salt } = walletVerificationChallenge.challenge;
214
204
  const challengeResponse = generateResponse(code.toString(), salt, secret);
215
205
  return {
216
206
  challengeResponse,
217
- challengeId: verificationChallenge.createWalletVerificationChallenge.id
207
+ verificationId
218
208
  };
219
209
  } catch (error) {
220
- if (error instanceof WalletVerificationChallengeError) {
210
+ if (error instanceof ChallengeError) {
221
211
  throw error;
222
212
  }
223
- throw new WalletVerificationChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
213
+ throw new ChallengeError("Failed to process wallet verification challenge", "CHALLENGE_PROCESSING_ERROR");
224
214
  }
225
215
  }
226
216
 
@@ -301,5 +291,5 @@ function createPortalClient(options, clientOptions) {
301
291
  }
302
292
 
303
293
  //#endregion
304
- export { ClientOptionsSchema, WalletVerificationChallengeError, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
294
+ export { ClientOptionsSchema, createPortalClient, getWebsocketClient, handleWalletVerificationChallenge, readFragment, waitForTransactionReceipt };
305
295
  //# sourceMappingURL=portal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"portal.js","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","options: ClientOptions","clientOptions?: RequestConfig"],"sources":["../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts","../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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 * Type representing the different types of wallet verification methods\n */\nexport type WalletVerificationType = \"PINCODE\" | \"OTP\" | \"SECRET_CODES\";\n\n/**\n * Custom error class for challenge-related errors\n */\nexport class WalletVerificationChallengeError 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 id: string;\n name: string;\n verificationId: string;\n verificationType: WalletVerificationType;\n challenge?: {\n salt: string;\n secret: string;\n };\n}\n\n/**\n * Response type for the CreateWalletVerificationChallenge mutation\n */\ninterface CreateWalletVerificationChallengeResponse {\n createWalletVerificationChallenge: 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: WalletVerificationType;\n /** Request id which can be added for tracing purposes */\n requestId?: string;\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 {WalletVerificationChallengeError} 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 requestId,\n}: HandleWalletVerificationChallengeOptions<Setup>): Promise<{\n challengeResponse: string;\n challengeId: string;\n}> {\n try {\n const requestHeaders = new Headers();\n if (requestId) {\n requestHeaders.append(\"x-request-id\", requestId);\n }\n const verificationChallenge = await portalClient.request<CreateWalletVerificationChallengeResponse>(\n portalGraphql(`\n mutation CreateWalletVerificationChallenge($userWalletAddress: String!, $verificationId: String!) {\n createWalletVerificationChallenge(\n userWalletAddress: $userWalletAddress\n verificationId: $verificationId\n ) {\n id\n name\n verificationId\n verificationType\n challenge {\n salt\n secret\n }\n }\n }\n `),\n {\n userWalletAddress,\n verificationId,\n },\n requestHeaders,\n );\n\n if (!verificationChallenge.createWalletVerificationChallenge) {\n throw new WalletVerificationChallengeError(\"No verification challenge received\", \"NO_CHALLENGES\");\n }\n\n if (verificationType === \"OTP\") {\n return {\n challengeResponse: code.toString(),\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n if (verificationType === \"SECRET_CODES\") {\n // Add a hyphen after every 5 characters to format the secret code\n const formattedCode = code.toString().replace(/(.{5})(?=.)/, \"$1-\");\n return {\n challengeResponse: formattedCode,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n }\n\n const { secret, salt } = verificationChallenge.createWalletVerificationChallenge.challenge ?? {};\n\n if (!secret || !salt) {\n throw new WalletVerificationChallengeError(\"Invalid challenge format\", \"INVALID_CHALLENGE\");\n }\n\n const challengeResponse = generateResponse(code.toString(), salt, secret);\n return {\n challengeResponse,\n challengeId: verificationChallenge.createWalletVerificationChallenge.id,\n };\n } catch (error) {\n if (error instanceof WalletVerificationChallengeError) {\n throw error;\n }\n throw new WalletVerificationChallengeError(\n \"Failed to process wallet verification challenge\",\n \"CHALLENGE_PROCESSING_ERROR\",\n );\n }\n}\n","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n WalletVerificationChallengeError,\n type WalletVerificationType,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":"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"}
1
+ {"version":3,"file":"portal.js","names":["url: URL","transactionHash: string","options: WaitForTransactionReceiptOptions","timeout: number","subscription: AsyncIterableIterator<FormattedExecutionResult<GetTransactionResponse, unknown>>","message: string","code: string","pincode: string","salt: string","challenge: string","options: ClientOptions","clientOptions?: RequestConfig"],"sources":["../src/utils/websocket-client.ts","../src/utils/wait-for-transaction-receipt.ts","../src/utils/wallet-verification-challenge.ts","../src/portal.ts"],"sourcesContent":["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 const graphqlEndpoint = setWsProtocol(new URL(portalGraphqlEndpoint));\n return createClient({\n url: accessToken\n ? `${graphqlEndpoint.protocol}//${graphqlEndpoint.host}/${accessToken}${graphqlEndpoint.pathname}${graphqlEndpoint.search}`\n : graphqlEndpoint.toString(),\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 */\nexport interface TransactionEvent {\n /** The name of the event that was emitted */\n eventName: string;\n /** The arguments emitted by the event */\n args: Record<string, unknown>;\n /** Indexed event parameters used for filtering and searching */\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","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\";\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 type { FragmentOf, ResultOf, VariablesOf } from \"gql.tada\";\nexport { readFragment } from \"gql.tada\";\nexport {\n type Transaction,\n type TransactionEvent,\n type TransactionReceipt,\n type WaitForTransactionReceiptOptions,\n waitForTransactionReceipt,\n} from \"./utils/wait-for-transaction-receipt.js\";\nexport {\n type HandleWalletVerificationChallengeOptions,\n handleWalletVerificationChallenge,\n} from \"./utils/wallet-verification-challenge.js\";\nexport { getWebsocketClient, type WebsocketClientOptions } from \"./utils/websocket-client.js\";\n"],"mappings":"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"}
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.5.14-pr4da67ef3",
4
+ "version": "2.5.14-pr9a38dbdb",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "FSL-1.1-MIT",
@@ -59,7 +59,7 @@
59
59
  "dependencies": {
60
60
  "gql.tada": "^1",
61
61
  "graphql-ws": "^6",
62
- "@settlemint/sdk-utils": "2.5.14-pr4da67ef3",
62
+ "@settlemint/sdk-utils": "2.5.14-pr9a38dbdb",
63
63
  "graphql-request": "^7",
64
64
  "zod": "^4"
65
65
  },