@metamask-previews/multichain-api-middleware 1.2.4-preview-ee982ebe → 1.2.4-preview-91b0ac79

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.
@@ -68,13 +68,13 @@ async function walletCreateSessionHandler(req, res, _next, end, hooks) {
68
68
  }
69
69
  const { supportedScopes: supportedRequiredScopes } = (0, chain_agnostic_permission_1.bucketScopes)(requiredScopesWithSupportedMethodsAndNotifications, {
70
70
  isEvmChainIdSupported: networkClientExistsForChainId,
71
- isEvmChainIdSupportable: () => false,
71
+ isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties
72
72
  getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,
73
73
  isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,
74
74
  });
75
75
  const { supportedScopes: supportedOptionalScopes } = (0, chain_agnostic_permission_1.bucketScopes)(optionalScopesWithSupportedMethodsAndNotifications, {
76
76
  isEvmChainIdSupported: networkClientExistsForChainId,
77
- isEvmChainIdSupportable: () => false,
77
+ isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties
78
78
  getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,
79
79
  isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,
80
80
  });
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-createSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-createSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n bucketScopes,\n validateAndNormalizeScopes,\n type Caip25Authorization,\n getInternalScopesObject,\n getSessionScopes,\n type NormalizedScopesObject,\n getSupportedScopeObjects,\n type Caip25CaveatValue,\n isKnownSessionPropertyValue,\n getCaipAccountIdsFromScopesObjects,\n getAllScopesFromScopesObjects,\n setNonSCACaipAccountIdsInCaip25CaveatValue,\n isNamespaceInScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport { isEqualCaseInsensitive } from '@metamask/controller-utils';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport type { NetworkController } from '@metamask/network-controller';\nimport {\n invalidParams,\n type RequestedPermissions,\n} from '@metamask/permission-controller';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport {\n type CaipAccountId,\n type CaipChainId,\n type Hex,\n isPlainObject,\n type Json,\n type JsonRpcRequest,\n type JsonRpcSuccess,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\n\nimport type { GrantedPermissions } from './types';\n\nconst SOLANA_CAIP_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/**\n * Handler for the `wallet_createSession` RPC method which is responsible\n * for prompting for approval and granting a CAIP-25 permission.\n *\n * This implementation primarily deviates from the CAIP-25 handler\n * specification by treating all scopes as optional regardless of\n * if they were specified in `requiredScopes` or `optionalScopes`.\n * Additionally, provided scopes, methods, notifications, and\n * account values that are invalid/malformed are ignored rather than\n * causing an error to be returned.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param _next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.listAccounts - The hook that returns an array of the wallet's evm accounts.\n * @param hooks.findNetworkClientIdByChainId - The hook that returns the networkClientId for a chainId.\n * @param hooks.requestPermissionsForOrigin - The hook that approves and grants requested permissions.\n * @param hooks.getNonEvmSupportedMethods - The hook that returns the supported methods for a non EVM scope.\n * @param hooks.isNonEvmScopeSupported - The hook that returns true if a non EVM scope is supported.\n * @param hooks.getNonEvmAccountAddresses - The hook that returns a list of CaipAccountIds that are supported for a CaipChainId.\n * @param hooks.trackSessionCreatedEvent - An optional hook for platform specific logic to run. Can be undefined.\n * @returns A promise with wallet_createSession handler\n */\nasync function walletCreateSessionHandler(\n req: JsonRpcRequest<Caip25Authorization> & { origin: string },\n res: JsonRpcSuccess<{\n sessionScopes: NormalizedScopesObject;\n sessionProperties?: Record<string, Json>;\n }>,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: {\n listAccounts: () => { address: string }[];\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n requestPermissionsForOrigin: (\n requestedPermissions: RequestedPermissions,\n metadata?: Record<string, Json>,\n ) => Promise<[GrantedPermissions]>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n isNonEvmScopeSupported: (scope: CaipChainId) => boolean;\n getNonEvmAccountAddresses: (scope: CaipChainId) => CaipAccountId[];\n trackSessionCreatedEvent?: (\n approvedCaip25CaveatValue: Caip25CaveatValue,\n ) => void;\n },\n) {\n if (!isPlainObject(req.params)) {\n return end(invalidParams({ data: { request: req } }));\n }\n const { requiredScopes, optionalScopes, sessionProperties } = req.params;\n\n if (sessionProperties && Object.keys(sessionProperties).length === 0) {\n return end(new JsonRpcError(5302, 'Invalid sessionProperties requested'));\n }\n\n const filteredSessionProperties = Object.fromEntries(\n Object.entries(sessionProperties ?? {}).filter(([key]) =>\n isKnownSessionPropertyValue(key),\n ),\n );\n\n try {\n const { normalizedRequiredScopes, normalizedOptionalScopes } =\n validateAndNormalizeScopes(requiredScopes || {}, optionalScopes || {});\n\n const requiredScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedRequiredScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n const optionalScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedOptionalScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const networkClientExistsForChainId = (chainId: Hex) => {\n try {\n hooks.findNetworkClientIdByChainId(chainId);\n return true;\n } catch {\n return false;\n }\n };\n\n // if solana is a requested scope but not supported, we add a promptToCreateSolanaAccount flag to request\n const isSolanaRequested =\n isNamespaceInScopesObject(\n requiredScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n ) ||\n isNamespaceInScopesObject(\n optionalScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n );\n\n let promptToCreateSolanaAccount = false;\n if (isSolanaRequested) {\n const supportedSolanaAccounts =\n hooks.getNonEvmAccountAddresses(SOLANA_CAIP_CHAIN_ID);\n promptToCreateSolanaAccount = supportedSolanaAccounts.length === 0;\n }\n\n const { supportedScopes: supportedRequiredScopes } = bucketScopes(\n requiredScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const { supportedScopes: supportedOptionalScopes } = bucketScopes(\n optionalScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const allRequestedAccountAddresses = getCaipAccountIdsFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const allSupportedRequestedCaipChainIds = getAllScopesFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const existingEvmAddresses = hooks\n .listAccounts()\n .map((account) => account.address);\n\n const supportedRequestedAccountAddresses =\n allRequestedAccountAddresses.filter(\n (requestedAccountAddress: CaipAccountId) => {\n const {\n address,\n chain: { namespace },\n chainId: caipChainId,\n } = parseCaipAccountId(requestedAccountAddress);\n if (namespace === KnownCaipNamespace.Eip155.toString()) {\n return existingEvmAddresses.some((existingEvmAddress) => {\n return isEqualCaseInsensitive(address, existingEvmAddress);\n });\n }\n\n // If the namespace is not eip155 (EVM) we do a case sensitive check\n return hooks\n .getNonEvmAccountAddresses(caipChainId)\n .some((existingCaipAddress) => {\n return requestedAccountAddress === existingCaipAddress;\n });\n },\n );\n\n const requestedCaip25CaveatValue = {\n requiredScopes: getInternalScopesObject(supportedRequiredScopes),\n optionalScopes: getInternalScopesObject(supportedOptionalScopes),\n isMultichainOrigin: true,\n sessionProperties: filteredSessionProperties,\n };\n\n const requestedCaip25CaveatValueWithSupportedAccounts =\n setNonSCACaipAccountIdsInCaip25CaveatValue(\n requestedCaip25CaveatValue,\n supportedRequestedAccountAddresses,\n );\n\n // if `promptToCreateSolanaAccount` is true and there are no other valid scopes requested,\n // we add a `wallet` scope to the request in order to get passed the CAIP-25 caveat validator.\n // This is very hacky but is necessary because the solana opt-in flow breaks key assumptions\n // of the CAIP-25 permission specification - namely that we can have valid requests with no scopes.\n if (allSupportedRequestedCaipChainIds.length === 0) {\n if (promptToCreateSolanaAccount) {\n requestedCaip25CaveatValueWithSupportedAccounts.optionalScopes[\n KnownCaipNamespace.Wallet\n ] = {\n accounts: [],\n };\n } else {\n // if solana is not requested and there are no supported scopes, we return an error\n return end(\n new JsonRpcError(5100, 'Requested scopes are not supported'),\n );\n }\n }\n\n const [grantedPermissions] = await hooks.requestPermissionsForOrigin(\n {\n [Caip25EndowmentPermissionName]: {\n caveats: [\n {\n type: Caip25CaveatType,\n value: requestedCaip25CaveatValueWithSupportedAccounts,\n },\n ],\n },\n },\n {\n metadata: { promptToCreateSolanaAccount },\n },\n );\n\n const approvedCaip25Permission =\n grantedPermissions[Caip25EndowmentPermissionName];\n const approvedCaip25CaveatValue = approvedCaip25Permission?.caveats?.find(\n (caveat) => caveat.type === Caip25CaveatType,\n )?.value as Caip25CaveatValue;\n if (!approvedCaip25CaveatValue) {\n throw rpcErrors.internal();\n }\n\n const sessionScopes = getSessionScopes(approvedCaip25CaveatValue, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const { sessionProperties: approvedSessionProperties = {} } =\n approvedCaip25CaveatValue;\n\n hooks.trackSessionCreatedEvent?.(approvedCaip25CaveatValue);\n\n res.result = {\n sessionScopes,\n sessionProperties: approvedSessionProperties,\n };\n return end();\n } catch (err) {\n return end(err);\n }\n}\n\nexport const walletCreateSession = {\n methodNames: ['wallet_createSession'],\n implementation: walletCreateSessionHandler,\n hookNames: {\n findNetworkClientIdByChainId: true,\n listAccounts: true,\n requestPermissionsForOrigin: true,\n getNonEvmSupportedMethods: true,\n isNonEvmScopeSupported: true,\n getNonEvmAccountAddresses: true,\n trackSessionCreatedEvent: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-createSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-createSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n bucketScopes,\n validateAndNormalizeScopes,\n type Caip25Authorization,\n getInternalScopesObject,\n getSessionScopes,\n type NormalizedScopesObject,\n getSupportedScopeObjects,\n type Caip25CaveatValue,\n isKnownSessionPropertyValue,\n getCaipAccountIdsFromScopesObjects,\n getAllScopesFromScopesObjects,\n setNonSCACaipAccountIdsInCaip25CaveatValue,\n isNamespaceInScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport { isEqualCaseInsensitive } from '@metamask/controller-utils';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport type { NetworkController } from '@metamask/network-controller';\nimport {\n invalidParams,\n type RequestedPermissions,\n} from '@metamask/permission-controller';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport {\n type CaipAccountId,\n type CaipChainId,\n type Hex,\n isPlainObject,\n type Json,\n type JsonRpcRequest,\n type JsonRpcSuccess,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\n\nimport type { GrantedPermissions } from './types';\n\nconst SOLANA_CAIP_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/**\n * Handler for the `wallet_createSession` RPC method which is responsible\n * for prompting for approval and granting a CAIP-25 permission.\n *\n * This implementation primarily deviates from the CAIP-25 handler\n * specification by treating all scopes as optional regardless of\n * if they were specified in `requiredScopes` or `optionalScopes`.\n * Additionally, provided scopes, methods, notifications, and\n * account values that are invalid/malformed are ignored rather than\n * causing an error to be returned.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param _next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.listAccounts - The hook that returns an array of the wallet's evm accounts.\n * @param hooks.findNetworkClientIdByChainId - The hook that returns the networkClientId for a chainId.\n * @param hooks.requestPermissionsForOrigin - The hook that approves and grants requested permissions.\n * @param hooks.getNonEvmSupportedMethods - The hook that returns the supported methods for a non EVM scope.\n * @param hooks.isNonEvmScopeSupported - The hook that returns true if a non EVM scope is supported.\n * @param hooks.getNonEvmAccountAddresses - The hook that returns a list of CaipAccountIds that are supported for a CaipChainId.\n * @param hooks.trackSessionCreatedEvent - An optional hook for platform specific logic to run. Can be undefined.\n * @returns A promise with wallet_createSession handler\n */\nasync function walletCreateSessionHandler(\n req: JsonRpcRequest<Caip25Authorization> & { origin: string },\n res: JsonRpcSuccess<{\n sessionScopes: NormalizedScopesObject;\n sessionProperties?: Record<string, Json>;\n }>,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: {\n listAccounts: () => { address: string }[];\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n requestPermissionsForOrigin: (\n requestedPermissions: RequestedPermissions,\n metadata?: Record<string, Json>,\n ) => Promise<[GrantedPermissions]>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n isNonEvmScopeSupported: (scope: CaipChainId) => boolean;\n getNonEvmAccountAddresses: (scope: CaipChainId) => CaipAccountId[];\n trackSessionCreatedEvent?: (\n approvedCaip25CaveatValue: Caip25CaveatValue,\n ) => void;\n },\n) {\n if (!isPlainObject(req.params)) {\n return end(invalidParams({ data: { request: req } }));\n }\n const { requiredScopes, optionalScopes, sessionProperties } = req.params;\n\n if (sessionProperties && Object.keys(sessionProperties).length === 0) {\n return end(new JsonRpcError(5302, 'Invalid sessionProperties requested'));\n }\n\n const filteredSessionProperties = Object.fromEntries(\n Object.entries(sessionProperties ?? {}).filter(([key]) =>\n isKnownSessionPropertyValue(key),\n ),\n );\n\n try {\n const { normalizedRequiredScopes, normalizedOptionalScopes } =\n validateAndNormalizeScopes(requiredScopes || {}, optionalScopes || {});\n\n const requiredScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedRequiredScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n const optionalScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedOptionalScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const networkClientExistsForChainId = (chainId: Hex) => {\n try {\n hooks.findNetworkClientIdByChainId(chainId);\n return true;\n } catch {\n return false;\n }\n };\n\n // if solana is a requested scope but not supported, we add a promptToCreateSolanaAccount flag to request\n const isSolanaRequested =\n isNamespaceInScopesObject(\n requiredScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n ) ||\n isNamespaceInScopesObject(\n optionalScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n );\n\n let promptToCreateSolanaAccount = false;\n if (isSolanaRequested) {\n const supportedSolanaAccounts =\n hooks.getNonEvmAccountAddresses(SOLANA_CAIP_CHAIN_ID);\n promptToCreateSolanaAccount = supportedSolanaAccounts.length === 0;\n }\n\n const { supportedScopes: supportedRequiredScopes } = bucketScopes(\n requiredScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const { supportedScopes: supportedOptionalScopes } = bucketScopes(\n optionalScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const allRequestedAccountAddresses = getCaipAccountIdsFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const allSupportedRequestedCaipChainIds = getAllScopesFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const existingEvmAddresses = hooks\n .listAccounts()\n .map((account) => account.address);\n\n const supportedRequestedAccountAddresses =\n allRequestedAccountAddresses.filter(\n (requestedAccountAddress: CaipAccountId) => {\n const {\n address,\n chain: { namespace },\n chainId: caipChainId,\n } = parseCaipAccountId(requestedAccountAddress);\n if (namespace === KnownCaipNamespace.Eip155.toString()) {\n return existingEvmAddresses.some((existingEvmAddress) => {\n return isEqualCaseInsensitive(address, existingEvmAddress);\n });\n }\n\n // If the namespace is not eip155 (EVM) we do a case sensitive check\n return hooks\n .getNonEvmAccountAddresses(caipChainId)\n .some((existingCaipAddress) => {\n return requestedAccountAddress === existingCaipAddress;\n });\n },\n );\n\n const requestedCaip25CaveatValue = {\n requiredScopes: getInternalScopesObject(supportedRequiredScopes),\n optionalScopes: getInternalScopesObject(supportedOptionalScopes),\n isMultichainOrigin: true,\n sessionProperties: filteredSessionProperties,\n };\n\n const requestedCaip25CaveatValueWithSupportedAccounts =\n setNonSCACaipAccountIdsInCaip25CaveatValue(\n requestedCaip25CaveatValue,\n supportedRequestedAccountAddresses,\n );\n\n // if `promptToCreateSolanaAccount` is true and there are no other valid scopes requested,\n // we add a `wallet` scope to the request in order to get passed the CAIP-25 caveat validator.\n // This is very hacky but is necessary because the solana opt-in flow breaks key assumptions\n // of the CAIP-25 permission specification - namely that we can have valid requests with no scopes.\n if (allSupportedRequestedCaipChainIds.length === 0) {\n if (promptToCreateSolanaAccount) {\n requestedCaip25CaveatValueWithSupportedAccounts.optionalScopes[\n KnownCaipNamespace.Wallet\n ] = {\n accounts: [],\n };\n } else {\n // if solana is not requested and there are no supported scopes, we return an error\n return end(\n new JsonRpcError(5100, 'Requested scopes are not supported'),\n );\n }\n }\n\n const [grantedPermissions] = await hooks.requestPermissionsForOrigin(\n {\n [Caip25EndowmentPermissionName]: {\n caveats: [\n {\n type: Caip25CaveatType,\n value: requestedCaip25CaveatValueWithSupportedAccounts,\n },\n ],\n },\n },\n {\n metadata: { promptToCreateSolanaAccount },\n },\n );\n\n const approvedCaip25Permission =\n grantedPermissions[Caip25EndowmentPermissionName];\n const approvedCaip25CaveatValue = approvedCaip25Permission?.caveats?.find(\n (caveat) => caveat.type === Caip25CaveatType,\n )?.value as Caip25CaveatValue;\n if (!approvedCaip25CaveatValue) {\n throw rpcErrors.internal();\n }\n\n const sessionScopes = getSessionScopes(approvedCaip25CaveatValue, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const { sessionProperties: approvedSessionProperties = {} } =\n approvedCaip25CaveatValue;\n\n hooks.trackSessionCreatedEvent?.(approvedCaip25CaveatValue);\n\n res.result = {\n sessionScopes,\n sessionProperties: approvedSessionProperties,\n };\n return end();\n } catch (err) {\n return end(err);\n }\n}\n\nexport const walletCreateSession = {\n methodNames: ['wallet_createSession'],\n implementation: walletCreateSessionHandler,\n hookNames: {\n findNetworkClientIdByChainId: true,\n listAccounts: true,\n requestPermissionsForOrigin: true,\n getNonEvmSupportedMethods: true,\n isNonEvmScopeSupported: true,\n getNonEvmAccountAddresses: true,\n trackSessionCreatedEvent: true,\n },\n};\n"]}
@@ -65,13 +65,13 @@ async function walletCreateSessionHandler(req, res, _next, end, hooks) {
65
65
  }
66
66
  const { supportedScopes: supportedRequiredScopes } = bucketScopes(requiredScopesWithSupportedMethodsAndNotifications, {
67
67
  isEvmChainIdSupported: networkClientExistsForChainId,
68
- isEvmChainIdSupportable: () => false,
68
+ isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties
69
69
  getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,
70
70
  isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,
71
71
  });
72
72
  const { supportedScopes: supportedOptionalScopes } = bucketScopes(optionalScopesWithSupportedMethodsAndNotifications, {
73
73
  isEvmChainIdSupported: networkClientExistsForChainId,
74
- isEvmChainIdSupportable: () => false,
74
+ isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties
75
75
  getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,
76
76
  isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,
77
77
  });
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-createSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-createSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n bucketScopes,\n validateAndNormalizeScopes,\n type Caip25Authorization,\n getInternalScopesObject,\n getSessionScopes,\n type NormalizedScopesObject,\n getSupportedScopeObjects,\n type Caip25CaveatValue,\n isKnownSessionPropertyValue,\n getCaipAccountIdsFromScopesObjects,\n getAllScopesFromScopesObjects,\n setNonSCACaipAccountIdsInCaip25CaveatValue,\n isNamespaceInScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport { isEqualCaseInsensitive } from '@metamask/controller-utils';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport type { NetworkController } from '@metamask/network-controller';\nimport {\n invalidParams,\n type RequestedPermissions,\n} from '@metamask/permission-controller';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport {\n type CaipAccountId,\n type CaipChainId,\n type Hex,\n isPlainObject,\n type Json,\n type JsonRpcRequest,\n type JsonRpcSuccess,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\n\nimport type { GrantedPermissions } from './types';\n\nconst SOLANA_CAIP_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/**\n * Handler for the `wallet_createSession` RPC method which is responsible\n * for prompting for approval and granting a CAIP-25 permission.\n *\n * This implementation primarily deviates from the CAIP-25 handler\n * specification by treating all scopes as optional regardless of\n * if they were specified in `requiredScopes` or `optionalScopes`.\n * Additionally, provided scopes, methods, notifications, and\n * account values that are invalid/malformed are ignored rather than\n * causing an error to be returned.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param _next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.listAccounts - The hook that returns an array of the wallet's evm accounts.\n * @param hooks.findNetworkClientIdByChainId - The hook that returns the networkClientId for a chainId.\n * @param hooks.requestPermissionsForOrigin - The hook that approves and grants requested permissions.\n * @param hooks.getNonEvmSupportedMethods - The hook that returns the supported methods for a non EVM scope.\n * @param hooks.isNonEvmScopeSupported - The hook that returns true if a non EVM scope is supported.\n * @param hooks.getNonEvmAccountAddresses - The hook that returns a list of CaipAccountIds that are supported for a CaipChainId.\n * @param hooks.trackSessionCreatedEvent - An optional hook for platform specific logic to run. Can be undefined.\n * @returns A promise with wallet_createSession handler\n */\nasync function walletCreateSessionHandler(\n req: JsonRpcRequest<Caip25Authorization> & { origin: string },\n res: JsonRpcSuccess<{\n sessionScopes: NormalizedScopesObject;\n sessionProperties?: Record<string, Json>;\n }>,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: {\n listAccounts: () => { address: string }[];\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n requestPermissionsForOrigin: (\n requestedPermissions: RequestedPermissions,\n metadata?: Record<string, Json>,\n ) => Promise<[GrantedPermissions]>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n isNonEvmScopeSupported: (scope: CaipChainId) => boolean;\n getNonEvmAccountAddresses: (scope: CaipChainId) => CaipAccountId[];\n trackSessionCreatedEvent?: (\n approvedCaip25CaveatValue: Caip25CaveatValue,\n ) => void;\n },\n) {\n if (!isPlainObject(req.params)) {\n return end(invalidParams({ data: { request: req } }));\n }\n const { requiredScopes, optionalScopes, sessionProperties } = req.params;\n\n if (sessionProperties && Object.keys(sessionProperties).length === 0) {\n return end(new JsonRpcError(5302, 'Invalid sessionProperties requested'));\n }\n\n const filteredSessionProperties = Object.fromEntries(\n Object.entries(sessionProperties ?? {}).filter(([key]) =>\n isKnownSessionPropertyValue(key),\n ),\n );\n\n try {\n const { normalizedRequiredScopes, normalizedOptionalScopes } =\n validateAndNormalizeScopes(requiredScopes || {}, optionalScopes || {});\n\n const requiredScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedRequiredScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n const optionalScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedOptionalScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const networkClientExistsForChainId = (chainId: Hex) => {\n try {\n hooks.findNetworkClientIdByChainId(chainId);\n return true;\n } catch {\n return false;\n }\n };\n\n // if solana is a requested scope but not supported, we add a promptToCreateSolanaAccount flag to request\n const isSolanaRequested =\n isNamespaceInScopesObject(\n requiredScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n ) ||\n isNamespaceInScopesObject(\n optionalScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n );\n\n let promptToCreateSolanaAccount = false;\n if (isSolanaRequested) {\n const supportedSolanaAccounts =\n hooks.getNonEvmAccountAddresses(SOLANA_CAIP_CHAIN_ID);\n promptToCreateSolanaAccount = supportedSolanaAccounts.length === 0;\n }\n\n const { supportedScopes: supportedRequiredScopes } = bucketScopes(\n requiredScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const { supportedScopes: supportedOptionalScopes } = bucketScopes(\n optionalScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const allRequestedAccountAddresses = getCaipAccountIdsFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const allSupportedRequestedCaipChainIds = getAllScopesFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const existingEvmAddresses = hooks\n .listAccounts()\n .map((account) => account.address);\n\n const supportedRequestedAccountAddresses =\n allRequestedAccountAddresses.filter(\n (requestedAccountAddress: CaipAccountId) => {\n const {\n address,\n chain: { namespace },\n chainId: caipChainId,\n } = parseCaipAccountId(requestedAccountAddress);\n if (namespace === KnownCaipNamespace.Eip155.toString()) {\n return existingEvmAddresses.some((existingEvmAddress) => {\n return isEqualCaseInsensitive(address, existingEvmAddress);\n });\n }\n\n // If the namespace is not eip155 (EVM) we do a case sensitive check\n return hooks\n .getNonEvmAccountAddresses(caipChainId)\n .some((existingCaipAddress) => {\n return requestedAccountAddress === existingCaipAddress;\n });\n },\n );\n\n const requestedCaip25CaveatValue = {\n requiredScopes: getInternalScopesObject(supportedRequiredScopes),\n optionalScopes: getInternalScopesObject(supportedOptionalScopes),\n isMultichainOrigin: true,\n sessionProperties: filteredSessionProperties,\n };\n\n const requestedCaip25CaveatValueWithSupportedAccounts =\n setNonSCACaipAccountIdsInCaip25CaveatValue(\n requestedCaip25CaveatValue,\n supportedRequestedAccountAddresses,\n );\n\n // if `promptToCreateSolanaAccount` is true and there are no other valid scopes requested,\n // we add a `wallet` scope to the request in order to get passed the CAIP-25 caveat validator.\n // This is very hacky but is necessary because the solana opt-in flow breaks key assumptions\n // of the CAIP-25 permission specification - namely that we can have valid requests with no scopes.\n if (allSupportedRequestedCaipChainIds.length === 0) {\n if (promptToCreateSolanaAccount) {\n requestedCaip25CaveatValueWithSupportedAccounts.optionalScopes[\n KnownCaipNamespace.Wallet\n ] = {\n accounts: [],\n };\n } else {\n // if solana is not requested and there are no supported scopes, we return an error\n return end(\n new JsonRpcError(5100, 'Requested scopes are not supported'),\n );\n }\n }\n\n const [grantedPermissions] = await hooks.requestPermissionsForOrigin(\n {\n [Caip25EndowmentPermissionName]: {\n caveats: [\n {\n type: Caip25CaveatType,\n value: requestedCaip25CaveatValueWithSupportedAccounts,\n },\n ],\n },\n },\n {\n metadata: { promptToCreateSolanaAccount },\n },\n );\n\n const approvedCaip25Permission =\n grantedPermissions[Caip25EndowmentPermissionName];\n const approvedCaip25CaveatValue = approvedCaip25Permission?.caveats?.find(\n (caveat) => caveat.type === Caip25CaveatType,\n )?.value as Caip25CaveatValue;\n if (!approvedCaip25CaveatValue) {\n throw rpcErrors.internal();\n }\n\n const sessionScopes = getSessionScopes(approvedCaip25CaveatValue, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const { sessionProperties: approvedSessionProperties = {} } =\n approvedCaip25CaveatValue;\n\n hooks.trackSessionCreatedEvent?.(approvedCaip25CaveatValue);\n\n res.result = {\n sessionScopes,\n sessionProperties: approvedSessionProperties,\n };\n return end();\n } catch (err) {\n return end(err);\n }\n}\n\nexport const walletCreateSession = {\n methodNames: ['wallet_createSession'],\n implementation: walletCreateSessionHandler,\n hookNames: {\n findNetworkClientIdByChainId: true,\n listAccounts: true,\n requestPermissionsForOrigin: true,\n getNonEvmSupportedMethods: true,\n isNonEvmScopeSupported: true,\n getNonEvmAccountAddresses: true,\n trackSessionCreatedEvent: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-createSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-createSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n bucketScopes,\n validateAndNormalizeScopes,\n type Caip25Authorization,\n getInternalScopesObject,\n getSessionScopes,\n type NormalizedScopesObject,\n getSupportedScopeObjects,\n type Caip25CaveatValue,\n isKnownSessionPropertyValue,\n getCaipAccountIdsFromScopesObjects,\n getAllScopesFromScopesObjects,\n setNonSCACaipAccountIdsInCaip25CaveatValue,\n isNamespaceInScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport { isEqualCaseInsensitive } from '@metamask/controller-utils';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport type { NetworkController } from '@metamask/network-controller';\nimport {\n invalidParams,\n type RequestedPermissions,\n} from '@metamask/permission-controller';\nimport { JsonRpcError, rpcErrors } from '@metamask/rpc-errors';\nimport {\n type CaipAccountId,\n type CaipChainId,\n type Hex,\n isPlainObject,\n type Json,\n type JsonRpcRequest,\n type JsonRpcSuccess,\n KnownCaipNamespace,\n parseCaipAccountId,\n} from '@metamask/utils';\n\nimport type { GrantedPermissions } from './types';\n\nconst SOLANA_CAIP_CHAIN_ID = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp';\n\n/**\n * Handler for the `wallet_createSession` RPC method which is responsible\n * for prompting for approval and granting a CAIP-25 permission.\n *\n * This implementation primarily deviates from the CAIP-25 handler\n * specification by treating all scopes as optional regardless of\n * if they were specified in `requiredScopes` or `optionalScopes`.\n * Additionally, provided scopes, methods, notifications, and\n * account values that are invalid/malformed are ignored rather than\n * causing an error to be returned.\n *\n * @param req - The request object.\n * @param res - The response object.\n * @param _next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.listAccounts - The hook that returns an array of the wallet's evm accounts.\n * @param hooks.findNetworkClientIdByChainId - The hook that returns the networkClientId for a chainId.\n * @param hooks.requestPermissionsForOrigin - The hook that approves and grants requested permissions.\n * @param hooks.getNonEvmSupportedMethods - The hook that returns the supported methods for a non EVM scope.\n * @param hooks.isNonEvmScopeSupported - The hook that returns true if a non EVM scope is supported.\n * @param hooks.getNonEvmAccountAddresses - The hook that returns a list of CaipAccountIds that are supported for a CaipChainId.\n * @param hooks.trackSessionCreatedEvent - An optional hook for platform specific logic to run. Can be undefined.\n * @returns A promise with wallet_createSession handler\n */\nasync function walletCreateSessionHandler(\n req: JsonRpcRequest<Caip25Authorization> & { origin: string },\n res: JsonRpcSuccess<{\n sessionScopes: NormalizedScopesObject;\n sessionProperties?: Record<string, Json>;\n }>,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: {\n listAccounts: () => { address: string }[];\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n requestPermissionsForOrigin: (\n requestedPermissions: RequestedPermissions,\n metadata?: Record<string, Json>,\n ) => Promise<[GrantedPermissions]>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n isNonEvmScopeSupported: (scope: CaipChainId) => boolean;\n getNonEvmAccountAddresses: (scope: CaipChainId) => CaipAccountId[];\n trackSessionCreatedEvent?: (\n approvedCaip25CaveatValue: Caip25CaveatValue,\n ) => void;\n },\n) {\n if (!isPlainObject(req.params)) {\n return end(invalidParams({ data: { request: req } }));\n }\n const { requiredScopes, optionalScopes, sessionProperties } = req.params;\n\n if (sessionProperties && Object.keys(sessionProperties).length === 0) {\n return end(new JsonRpcError(5302, 'Invalid sessionProperties requested'));\n }\n\n const filteredSessionProperties = Object.fromEntries(\n Object.entries(sessionProperties ?? {}).filter(([key]) =>\n isKnownSessionPropertyValue(key),\n ),\n );\n\n try {\n const { normalizedRequiredScopes, normalizedOptionalScopes } =\n validateAndNormalizeScopes(requiredScopes || {}, optionalScopes || {});\n\n const requiredScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedRequiredScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n const optionalScopesWithSupportedMethodsAndNotifications =\n getSupportedScopeObjects(normalizedOptionalScopes, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const networkClientExistsForChainId = (chainId: Hex) => {\n try {\n hooks.findNetworkClientIdByChainId(chainId);\n return true;\n } catch {\n return false;\n }\n };\n\n // if solana is a requested scope but not supported, we add a promptToCreateSolanaAccount flag to request\n const isSolanaRequested =\n isNamespaceInScopesObject(\n requiredScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n ) ||\n isNamespaceInScopesObject(\n optionalScopesWithSupportedMethodsAndNotifications,\n KnownCaipNamespace.Solana,\n );\n\n let promptToCreateSolanaAccount = false;\n if (isSolanaRequested) {\n const supportedSolanaAccounts =\n hooks.getNonEvmAccountAddresses(SOLANA_CAIP_CHAIN_ID);\n promptToCreateSolanaAccount = supportedSolanaAccounts.length === 0;\n }\n\n const { supportedScopes: supportedRequiredScopes } = bucketScopes(\n requiredScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const { supportedScopes: supportedOptionalScopes } = bucketScopes(\n optionalScopesWithSupportedMethodsAndNotifications,\n {\n isEvmChainIdSupported: networkClientExistsForChainId,\n isEvmChainIdSupportable: () => false, // intended for future usage with eip3085 scopedProperties\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n isNonEvmScopeSupported: hooks.isNonEvmScopeSupported,\n },\n );\n\n const allRequestedAccountAddresses = getCaipAccountIdsFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const allSupportedRequestedCaipChainIds = getAllScopesFromScopesObjects([\n supportedRequiredScopes,\n supportedOptionalScopes,\n ]);\n\n const existingEvmAddresses = hooks\n .listAccounts()\n .map((account) => account.address);\n\n const supportedRequestedAccountAddresses =\n allRequestedAccountAddresses.filter(\n (requestedAccountAddress: CaipAccountId) => {\n const {\n address,\n chain: { namespace },\n chainId: caipChainId,\n } = parseCaipAccountId(requestedAccountAddress);\n if (namespace === KnownCaipNamespace.Eip155.toString()) {\n return existingEvmAddresses.some((existingEvmAddress) => {\n return isEqualCaseInsensitive(address, existingEvmAddress);\n });\n }\n\n // If the namespace is not eip155 (EVM) we do a case sensitive check\n return hooks\n .getNonEvmAccountAddresses(caipChainId)\n .some((existingCaipAddress) => {\n return requestedAccountAddress === existingCaipAddress;\n });\n },\n );\n\n const requestedCaip25CaveatValue = {\n requiredScopes: getInternalScopesObject(supportedRequiredScopes),\n optionalScopes: getInternalScopesObject(supportedOptionalScopes),\n isMultichainOrigin: true,\n sessionProperties: filteredSessionProperties,\n };\n\n const requestedCaip25CaveatValueWithSupportedAccounts =\n setNonSCACaipAccountIdsInCaip25CaveatValue(\n requestedCaip25CaveatValue,\n supportedRequestedAccountAddresses,\n );\n\n // if `promptToCreateSolanaAccount` is true and there are no other valid scopes requested,\n // we add a `wallet` scope to the request in order to get passed the CAIP-25 caveat validator.\n // This is very hacky but is necessary because the solana opt-in flow breaks key assumptions\n // of the CAIP-25 permission specification - namely that we can have valid requests with no scopes.\n if (allSupportedRequestedCaipChainIds.length === 0) {\n if (promptToCreateSolanaAccount) {\n requestedCaip25CaveatValueWithSupportedAccounts.optionalScopes[\n KnownCaipNamespace.Wallet\n ] = {\n accounts: [],\n };\n } else {\n // if solana is not requested and there are no supported scopes, we return an error\n return end(\n new JsonRpcError(5100, 'Requested scopes are not supported'),\n );\n }\n }\n\n const [grantedPermissions] = await hooks.requestPermissionsForOrigin(\n {\n [Caip25EndowmentPermissionName]: {\n caveats: [\n {\n type: Caip25CaveatType,\n value: requestedCaip25CaveatValueWithSupportedAccounts,\n },\n ],\n },\n },\n {\n metadata: { promptToCreateSolanaAccount },\n },\n );\n\n const approvedCaip25Permission =\n grantedPermissions[Caip25EndowmentPermissionName];\n const approvedCaip25CaveatValue = approvedCaip25Permission?.caveats?.find(\n (caveat) => caveat.type === Caip25CaveatType,\n )?.value as Caip25CaveatValue;\n if (!approvedCaip25CaveatValue) {\n throw rpcErrors.internal();\n }\n\n const sessionScopes = getSessionScopes(approvedCaip25CaveatValue, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n });\n\n const { sessionProperties: approvedSessionProperties = {} } =\n approvedCaip25CaveatValue;\n\n hooks.trackSessionCreatedEvent?.(approvedCaip25CaveatValue);\n\n res.result = {\n sessionScopes,\n sessionProperties: approvedSessionProperties,\n };\n return end();\n } catch (err) {\n return end(err);\n }\n}\n\nexport const walletCreateSession = {\n methodNames: ['wallet_createSession'],\n implementation: walletCreateSessionHandler,\n hookNames: {\n findNetworkClientIdByChainId: true,\n listAccounts: true,\n requestPermissionsForOrigin: true,\n getNonEvmSupportedMethods: true,\n isNonEvmScopeSupported: true,\n getNonEvmAccountAddresses: true,\n trackSessionCreatedEvent: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-getSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-getSession.ts"],"names":[],"mappings":";;;AAIA,mFAI6C;AAQ7C;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAA6C,EAC7C,QAAmE,EACnE,KAAiB,EACjB,GAAe,EACf,KAMC;IAED,IAAI,MAAM,CAAC;IACX,IAAI;QACF,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAC/B,yDAA6B,EAC7B,4CAAgB,CACjB,CAAC;KACH;IAAC,MAAM;QACN,OAAO;KACR;IAED,IAAI,CAAC,MAAM,EAAE;QACX,QAAQ,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC;KACd;IAED,QAAQ,CAAC,MAAM,GAAG;QAChB,aAAa,EAAE,IAAA,4CAAgB,EAAC,MAAM,CAAC,KAAK,EAAE;YAC5C,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;SAC3D,CAAC;KACH,CAAC;IACF,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAEY,QAAA,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC,mBAAmB,CAAC;IAClC,cAAc,EAAE,uBAAuB;IACvC,SAAS,EAAE;QACT,kBAAkB,EAAE,IAAI;QACxB,yBAAyB,EAAE,IAAI;KAChC;CACF,CAAC","sourcesContent":["import type {\n Caip25CaveatValue,\n NormalizedScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getSessionScopes,\n} from '@metamask/chain-agnostic-permission';\nimport type { Caveat } from '@metamask/permission-controller';\nimport type {\n CaipChainId,\n JsonRpcRequest,\n JsonRpcSuccess,\n} from '@metamask/utils';\n\n/**\n * Handler for the `wallet_getSession` RPC method as specified by [CAIP-312](https://chainagnostic.org/CAIPs/caip-312).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param entirely,\n * and that an empty object is returned for the `sessionScopes` result rather than throwing an error if there\n * is no active session for the origin.\n *\n * @param _request - The request object.\n * @param response - The response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @returns Nothing.\n */\nasync function walletGetSessionHandler(\n _request: JsonRpcRequest & { origin: string },\n response: JsonRpcSuccess<{ sessionScopes: NormalizedScopesObject }>,\n _next: () => void,\n end: () => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n },\n) {\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n\n if (!caveat) {\n response.result = { sessionScopes: {} };\n return end();\n }\n\n response.result = {\n sessionScopes: getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n }),\n };\n return end();\n}\n\nexport const walletGetSession = {\n methodNames: ['wallet_getSession'],\n implementation: walletGetSessionHandler,\n hookNames: {\n getCaveatForOrigin: true,\n getNonEvmSupportedMethods: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-getSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-getSession.ts"],"names":[],"mappings":";;;AAIA,mFAI6C;AAQ7C;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAA6C,EAC7C,QAAmE,EACnE,KAAiB,EACjB,GAAe,EACf,KAMC;IAED,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAC/B,yDAA6B,EAC7B,4CAAgB,CACjB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,QAAQ,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,QAAQ,CAAC,MAAM,GAAG;QAChB,aAAa,EAAE,IAAA,4CAAgB,EAAC,MAAM,CAAC,KAAK,EAAE;YAC5C,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;SAC3D,CAAC;KACH,CAAC;IACF,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAEY,QAAA,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC,mBAAmB,CAAC;IAClC,cAAc,EAAE,uBAAuB;IACvC,SAAS,EAAE;QACT,kBAAkB,EAAE,IAAI;QACxB,yBAAyB,EAAE,IAAI;KAChC;CACF,CAAC","sourcesContent":["import type {\n Caip25CaveatValue,\n NormalizedScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getSessionScopes,\n} from '@metamask/chain-agnostic-permission';\nimport type { Caveat } from '@metamask/permission-controller';\nimport type {\n CaipChainId,\n JsonRpcRequest,\n JsonRpcSuccess,\n} from '@metamask/utils';\n\n/**\n * Handler for the `wallet_getSession` RPC method as specified by [CAIP-312](https://chainagnostic.org/CAIPs/caip-312).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param entirely,\n * and that an empty object is returned for the `sessionScopes` result rather than throwing an error if there\n * is no active session for the origin.\n *\n * @param _request - The request object.\n * @param response - The response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @returns Nothing.\n */\nasync function walletGetSessionHandler(\n _request: JsonRpcRequest & { origin: string },\n response: JsonRpcSuccess<{ sessionScopes: NormalizedScopesObject }>,\n _next: () => void,\n end: () => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n },\n) {\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n\n if (!caveat) {\n response.result = { sessionScopes: {} };\n return end();\n }\n\n response.result = {\n sessionScopes: getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n }),\n };\n return end();\n}\n\nexport const walletGetSession = {\n methodNames: ['wallet_getSession'],\n implementation: walletGetSessionHandler,\n hookNames: {\n getCaveatForOrigin: true,\n getNonEvmSupportedMethods: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-getSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-getSession.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,EAChB,6BAA6B,EAC7B,gBAAgB,EACjB,4CAA4C;AAQ7C;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAA6C,EAC7C,QAAmE,EACnE,KAAiB,EACjB,GAAe,EACf,KAMC;IAED,IAAI,MAAM,CAAC;IACX,IAAI;QACF,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAC/B,6BAA6B,EAC7B,gBAAgB,CACjB,CAAC;KACH;IAAC,MAAM;QACN,OAAO;KACR;IAED,IAAI,CAAC,MAAM,EAAE;QACX,QAAQ,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC;KACd;IAED,QAAQ,CAAC,MAAM,GAAG;QAChB,aAAa,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE;YAC5C,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;SAC3D,CAAC;KACH,CAAC;IACF,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC,mBAAmB,CAAC;IAClC,cAAc,EAAE,uBAAuB;IACvC,SAAS,EAAE;QACT,kBAAkB,EAAE,IAAI;QACxB,yBAAyB,EAAE,IAAI;KAChC;CACF,CAAC","sourcesContent":["import type {\n Caip25CaveatValue,\n NormalizedScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getSessionScopes,\n} from '@metamask/chain-agnostic-permission';\nimport type { Caveat } from '@metamask/permission-controller';\nimport type {\n CaipChainId,\n JsonRpcRequest,\n JsonRpcSuccess,\n} from '@metamask/utils';\n\n/**\n * Handler for the `wallet_getSession` RPC method as specified by [CAIP-312](https://chainagnostic.org/CAIPs/caip-312).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param entirely,\n * and that an empty object is returned for the `sessionScopes` result rather than throwing an error if there\n * is no active session for the origin.\n *\n * @param _request - The request object.\n * @param response - The response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @returns Nothing.\n */\nasync function walletGetSessionHandler(\n _request: JsonRpcRequest & { origin: string },\n response: JsonRpcSuccess<{ sessionScopes: NormalizedScopesObject }>,\n _next: () => void,\n end: () => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n },\n) {\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n\n if (!caveat) {\n response.result = { sessionScopes: {} };\n return end();\n }\n\n response.result = {\n sessionScopes: getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n }),\n };\n return end();\n}\n\nexport const walletGetSession = {\n methodNames: ['wallet_getSession'],\n implementation: walletGetSessionHandler,\n hookNames: {\n getCaveatForOrigin: true,\n getNonEvmSupportedMethods: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-getSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-getSession.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,gBAAgB,EAChB,6BAA6B,EAC7B,gBAAgB,EACjB,4CAA4C;AAQ7C;;;;;;;;;;;;;;GAcG;AACH,KAAK,UAAU,uBAAuB,CACpC,QAA6C,EAC7C,QAAmE,EACnE,KAAiB,EACjB,GAAe,EACf,KAMC;IAED,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAC/B,6BAA6B,EAC7B,gBAAgB,CACjB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,QAAQ,CAAC,MAAM,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC;IACf,CAAC;IAED,QAAQ,CAAC,MAAM,GAAG;QAChB,aAAa,EAAE,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE;YAC5C,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;SAC3D,CAAC;KACH,CAAC;IACF,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EAAE,CAAC,mBAAmB,CAAC;IAClC,cAAc,EAAE,uBAAuB;IACvC,SAAS,EAAE;QACT,kBAAkB,EAAE,IAAI;QACxB,yBAAyB,EAAE,IAAI;KAChC;CACF,CAAC","sourcesContent":["import type {\n Caip25CaveatValue,\n NormalizedScopesObject,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getSessionScopes,\n} from '@metamask/chain-agnostic-permission';\nimport type { Caveat } from '@metamask/permission-controller';\nimport type {\n CaipChainId,\n JsonRpcRequest,\n JsonRpcSuccess,\n} from '@metamask/utils';\n\n/**\n * Handler for the `wallet_getSession` RPC method as specified by [CAIP-312](https://chainagnostic.org/CAIPs/caip-312).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param entirely,\n * and that an empty object is returned for the `sessionScopes` result rather than throwing an error if there\n * is no active session for the origin.\n *\n * @param _request - The request object.\n * @param response - The response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - Function to retrieve a caveat for the origin.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @returns Nothing.\n */\nasync function walletGetSessionHandler(\n _request: JsonRpcRequest & { origin: string },\n response: JsonRpcSuccess<{ sessionScopes: NormalizedScopesObject }>,\n _next: () => void,\n end: () => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n },\n) {\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n\n if (!caveat) {\n response.result = { sessionScopes: {} };\n return end();\n }\n\n response.result = {\n sessionScopes: getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n }),\n };\n return end();\n}\n\nexport const walletGetSession = {\n methodNames: ['wallet_getSession'],\n implementation: walletGetSessionHandler,\n hookNames: {\n getCaveatForOrigin: true,\n getNonEvmSupportedMethods: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-invokeMethod.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":";;;AAIA,mFAM6C;AAG7C,qDAAiE;AASjE,2CAAkE;AAUlE;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,UAAU,yBAAyB,CACtC,OAAkC,EAClC,QAAgC,EAChC,IAAgB,EAChB,GAA4B,EAC5B,KAaC;IAED,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAE1D,IAAA,uDAA2B,EAAC,KAAK,CAAC,CAAC;IAEnC,IAAI,MAAM,CAAC;IACX,IAAI;QACF,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAC/B,yDAA6B,EAC7B,4CAAgB,CACjB,CAAC;KACH;IAAC,MAAM;QACN,OAAO;KACR;IACD,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,GAAG,CAAC,2BAAc,CAAC,YAAY,EAAE,CAAC,CAAC;KAC3C;IAED,MAAM,WAAW,GAAG,IAAA,4CAAgB,EAAC,MAAM,CAAC,KAAK,EAAE;QACjD,yBAAyB,EAAE,KAAK,CAAC,yBAAyB;KAC3D,CAAC,CAAC,KAAK,CAAC,CAAC;IAEV,IAAI,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE;QAC1D,OAAO,GAAG,CAAC,2BAAc,CAAC,YAAY,EAAE,CAAC,CAAC;KAC3C;IAED,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,IAAA,4CAAgB,EAAC,KAAK,CAAC,CAAC;IAEzD,MAAM,YAAY,GAChB,CAAC,SAAS,KAAK,0BAAkB,CAAC,MAAM;QACtC,CAAC,CAAC,SAAS,IAAI,SAAS,KAAK,0BAAkB,CAAC,MAAM,CAAC,CAAC;QAC1D,SAAS,KAAK,0BAAkB,CAAC,MAAM,CAAC;IAE1C,MAAM,gBAAgB,GAAG;QACvB,GAAG,OAAO;QACV,KAAK;QACL,MAAM,EAAE,cAAc,CAAC,MAAM;QAC7B,MAAM,EAAE,cAAc,CAAC,MAAM;KAC9B,CAAC;IAEF,IAAI,YAAY,EAAE;QAChB,IAAI,eAAe,CAAC;QACpB,IAAI,SAAS,KAAK,0BAAkB,CAAC,MAAM,EAAE;YAC3C,eAAe,GAAG,KAAK,CAAC,0BAA0B,EAAE,CAAC;SACtD;aAAM,IAAI,SAAS,KAAK,0BAAkB,CAAC,MAAM,EAAE;YAClD,IAAI,SAAS,EAAE;gBACb,eAAe,GAAG,KAAK,CAAC,4BAA4B,CAClD,IAAA,mBAAW,EAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CACrC,CAAC;aACH;SACF;QAED,IAAI,CAAC,eAAe,EAAE;YACpB,OAAO,CAAC,KAAK,CACX,0DAA0D,EAC1D,OAAO,CACR,CAAC;YACF,OAAO,GAAG,CAAC,sBAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;SAClC;QAED,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;YACrB,GAAG,gBAAgB;YACnB,eAAe;SAChB,CAAC,CAAC;QACH,OAAO,IAAI,EAAE,CAAC;KACf;IAED,IAAI;QACF,QAAQ,CAAC,MAAM,GAAG,MAAM,KAAK,CAAC,4BAA4B,CAAC;YACzD,kBAAkB,EAAE,WAAW,CAAC,QAAQ;YACxC,uEAAuE;YACvE,kCAAkC;YAClC,KAAK,EAAE,KAAoB;YAC3B,OAAO,EAAE,gBAAgB;SAC1B,CAAC,CAAC;KACJ;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,GAAG,CAAC,GAAY,CAAC,CAAC;KAC1B;IACD,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AACY,QAAA,kBAAkB,GAAG;IAChC,WAAW,EAAE,CAAC,qBAAqB,CAAC;IACpC,cAAc,EAAE,yBAAyB;IACzC,SAAS,EAAE;QACT,kBAAkB,EAAE,IAAI;QACxB,4BAA4B,EAAE,IAAI;QAClC,0BAA0B,EAAE,IAAI;QAChC,yBAAyB,EAAE,IAAI;QAC/B,4BAA4B,EAAE,IAAI;KACnC;CACF,CAAC","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-invokeMethod.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-invokeMethod.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-invokeMethod.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-invokeMethod.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n Caip25CaveatValue,\n ExternalScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport {\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n assertIsInternalScopeString,\n getSessionScopes,\n parseScopeString,\n} from '@metamask/chain-agnostic-permission';\nimport type { NetworkClientId } from '@metamask/network-controller';\nimport type { Caveat } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport type {\n CaipAccountId,\n CaipChainId,\n Hex,\n Json,\n JsonRpcRequest,\n PendingJsonRpcResponse,\n} from '@metamask/utils';\nimport { KnownCaipNamespace, numberToHex } from '@metamask/utils';\n\nexport type WalletInvokeMethodRequest = JsonRpcRequest & {\n origin: string;\n params: {\n scope: ExternalScopeString;\n request: Pick<JsonRpcRequest, 'method' | 'params'>;\n };\n};\n\n/**\n * Handler for the `wallet_invokeMethod` RPC method as specified by [CAIP-27](https://chainagnostic.org/CAIPs/caip-27).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead uses the singular session for the origin if available.\n *\n * @param request - The request object.\n * @param response - The response object. Unused.\n * @param next - The next middleware function.\n * @param end - The end function.\n * @param hooks - The hooks object.\n * @param hooks.getCaveatForOrigin - the hook for getting a caveat from a permission for an origin.\n * @param hooks.findNetworkClientIdByChainId - the hook for finding the networkClientId for a chainId.\n * @param hooks.getSelectedNetworkClientId - the hook for getting the current globally selected networkClientId.\n * @param hooks.getNonEvmSupportedMethods - A function that returns the supported methods for a non EVM scope.\n * @param hooks.handleNonEvmRequestForOrigin - A function that sends a request to the MultichainRouter for processing.\n * @returns Nothing.\n */\nasync function walletInvokeMethodHandler(\n request: WalletInvokeMethodRequest,\n response: PendingJsonRpcResponse,\n next: () => void,\n end: (error?: Error) => void,\n hooks: {\n getCaveatForOrigin: (\n endowmentPermissionName: string,\n caveatType: string,\n ) => Caveat<typeof Caip25CaveatType, Caip25CaveatValue>;\n findNetworkClientIdByChainId: (chainId: Hex) => NetworkClientId | undefined;\n getSelectedNetworkClientId: () => NetworkClientId;\n getNonEvmSupportedMethods: (scope: CaipChainId) => string[];\n handleNonEvmRequestForOrigin: (params: {\n connectedAddresses: CaipAccountId[];\n scope: CaipChainId;\n request: JsonRpcRequest;\n }) => Promise<Json>;\n },\n) {\n const { scope, request: wrappedRequest } = request.params;\n\n assertIsInternalScopeString(scope);\n\n let caveat;\n try {\n caveat = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n );\n } catch {\n // noop\n }\n if (!caveat) {\n return end(providerErrors.unauthorized());\n }\n\n const scopeObject = getSessionScopes(caveat.value, {\n getNonEvmSupportedMethods: hooks.getNonEvmSupportedMethods,\n })[scope];\n\n if (!scopeObject?.methods?.includes(wrappedRequest.method)) {\n return end(providerErrors.unauthorized());\n }\n\n const { namespace, reference } = parseScopeString(scope);\n\n const isEvmRequest =\n (namespace === KnownCaipNamespace.Wallet &&\n (!reference || reference === KnownCaipNamespace.Eip155)) ||\n namespace === KnownCaipNamespace.Eip155;\n\n const unwrappedRequest = {\n ...request,\n scope,\n method: wrappedRequest.method,\n params: wrappedRequest.params,\n };\n\n if (isEvmRequest) {\n let networkClientId;\n if (namespace === KnownCaipNamespace.Wallet) {\n networkClientId = hooks.getSelectedNetworkClientId();\n } else if (namespace === KnownCaipNamespace.Eip155) {\n if (reference) {\n networkClientId = hooks.findNetworkClientIdByChainId(\n numberToHex(parseInt(reference, 10)),\n );\n }\n }\n\n if (!networkClientId) {\n console.error(\n 'failed to resolve network client for wallet_invokeMethod',\n request,\n );\n return end(rpcErrors.internal());\n }\n\n Object.assign(request, {\n ...unwrappedRequest,\n networkClientId,\n });\n return next();\n }\n\n try {\n response.result = await hooks.handleNonEvmRequestForOrigin({\n connectedAddresses: scopeObject.accounts,\n // Type assertion: We know that scope is not \"wallet\" by now because it\n // is already being handled above.\n scope: scope as CaipChainId,\n request: unwrappedRequest,\n });\n } catch (err) {\n return end(err as Error);\n }\n return end();\n}\nexport const walletInvokeMethod = {\n methodNames: ['wallet_invokeMethod'],\n implementation: walletInvokeMethodHandler,\n hookNames: {\n getCaveatForOrigin: true,\n findNetworkClientIdByChainId: true,\n getSelectedNetworkClientId: true,\n getNonEvmSupportedMethods: true,\n handleNonEvmRequestForOrigin: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-revokeSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-revokeSession.ts"],"names":[],"mappings":";;;AAAA,mFAK6C;AAK7C,2EAIyC;AACzC,qDAAiD;AACjD,2CAIyB;AAIzB;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IACE,CAAC,IAAA,gBAAQ,EAAC,KAAK,CAAC;QAChB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QAClB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAC9B;QACA,OAAO,KAAK,CAAC;KACd;IAED,OAAO;QACL,gDAAwB,CAAC,IAAI;QAC7B,mDAA2B,CAAC,IAAI;KACjC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wBAAwB,CAC/B,MAAgB,EAChB,KAA+B;IAE/B,IAAI,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAC/C,yDAA6B,EAC7B,4CAAgB,CACjB,CAAC,KAAK,CAAC;IAER,KAAK,MAAM,WAAW,IAAI,MAAM,EAAE;QAChC,MAAM,MAAM,GAAG,gDAAoB,CAAC,4CAAgB,CAAC,CAAC,WAAW,CAC/D,kBAAkB,EAClB,WAAW,CACZ,CAAC;QAEF,0HAA0H;QAC1H,IAAI,MAAM,CAAC,SAAS,KAAK,8CAAsB,CAAC,IAAI,EAAE;YACpD,SAAS;SACV;QAED,kBAAkB,GAAG,MAAM,EAAE,KAAK,IAAI;YACpC,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,iBAAiB,EAAE,EAAE;YACrB,kBAAkB,EAAE,IAAI;SACzB,CAAC;KACH;IAED,MAAM,cAAc,GAClB,IAAA,kEAAsC,EAAC,kBAAkB,CAAC,CAAC;IAE7D,+EAA+E;IAC/E,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QAC1B,KAAK,CAAC,yBAAyB,CAAC,yDAA6B,CAAC,CAAC;KAChE;SAAM;QACL,KAAK,CAAC,YAAY,CAChB,yDAA6B,EAC7B,4CAAgB,EAChB,kBAAkB,CACnB,CAAC;KACH;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,UAAU,0BAA0B,CACvC,OAGC,EACD,QAAwB,EACxB,KAAgC,EAChC,GAA6B,EAC7B,KAA+B;IAE/B,MAAM,EACJ,MAAM,EAAE,EAAE,MAAM,EAAE,GACnB,GAAG,OAAO,CAAC;IAEZ,IAAI;QACF,IAAI,MAAM,EAAE,MAAM,EAAE;YAClB,wBAAwB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,yBAAyB,CAAC,yDAA6B,CAAC,CAAC;SAChE;KACF;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE;YAC3B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,sBAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;SAClC;KACF;IAED,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AACY,QAAA,mBAAmB,GAAG;IACjC,WAAW,EAAE,CAAC,sBAAsB,CAAC;IACrC,cAAc,EAAE,0BAA0B;IAC1C,SAAS,EAAE;QACT,yBAAyB,EAAE,IAAI;QAC/B,YAAY,EAAE,IAAI;QAClB,kBAAkB,EAAE,IAAI;KACzB;CACF,CAAC","sourcesContent":["import {\n Caip25CaveatMutators,\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getCaipAccountIdsFromCaip25CaveatValue,\n} from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineNextCallback,\n JsonRpcEngineEndCallback,\n} from '@metamask/json-rpc-engine';\nimport {\n CaveatMutatorOperation,\n PermissionDoesNotExistError,\n UnrecognizedSubjectError,\n} from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n type JsonRpcSuccess,\n type JsonRpcRequest,\n isObject,\n} from '@metamask/utils';\n\nimport type { WalletRevokeSessionHooks } from './types';\n\n/**\n * Check whether the given error is a permission error.\n *\n * @param error - The error to check.\n * @returns Whether the error is a permission error.\n */\nfunction isPermissionError(error: unknown) {\n if (\n !isObject(error) ||\n !('name' in error) ||\n typeof error.name !== 'string'\n ) {\n return false;\n }\n\n return [\n UnrecognizedSubjectError.name,\n PermissionDoesNotExistError.name,\n ].includes(error.name);\n}\n\n/**\n * Revokes specific session scopes from an existing caveat.\n * Fully revokes permission if no accounts remain permitted after iterating through scopes.\n *\n * @param scopes - Array of scope strings to remove from the caveat.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n */\nfunction partialRevokePermissions(\n scopes: string[],\n hooks: WalletRevokeSessionHooks,\n) {\n let updatedCaveatValue = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n ).value;\n\n for (const scopeString of scopes) {\n const result = Caip25CaveatMutators[Caip25CaveatType].removeScope(\n updatedCaveatValue,\n scopeString,\n );\n\n // If operation is a Noop, it means a scope was passed that was not present in the permission, so we proceed with the loop\n if (result.operation === CaveatMutatorOperation.Noop) {\n continue;\n }\n\n updatedCaveatValue = result?.value ?? {\n requiredScopes: {},\n optionalScopes: {},\n sessionProperties: {},\n isMultichainOrigin: true,\n };\n }\n\n const caipAccountIds =\n getCaipAccountIdsFromCaip25CaveatValue(updatedCaveatValue);\n\n // We fully revoke permission if no accounts are left after scope removal loop.\n if (!caipAccountIds.length) {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n } else {\n hooks.updateCaveat(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n updatedCaveatValue,\n );\n }\n}\n\n/**\n * Handler for the `wallet_revokeSession` RPC method as specified by [CAIP-285](https://chainagnostic.org/CAIPs/caip-285).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead revokes the singular session for the origin if available. Additionally,\n * the handler also does not return an error if there is currently no active session and instead\n * returns true which is the same result returned if an active session was actually revoked.\n *\n * @param request - The JSON-RPC request object. Unused.\n * @param response - The JSON-RPC response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end callback function.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n * @returns Nothing.\n */\nasync function walletRevokeSessionHandler(\n request: JsonRpcRequest & {\n origin: string;\n params: { scopes?: string[] };\n },\n response: JsonRpcSuccess,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: WalletRevokeSessionHooks,\n) {\n const {\n params: { scopes },\n } = request;\n\n try {\n if (scopes?.length) {\n partialRevokePermissions(scopes, hooks);\n } else {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n }\n } catch (err) {\n if (!isPermissionError(err)) {\n console.error(err);\n return end(rpcErrors.internal());\n }\n }\n\n response.result = true;\n return end();\n}\nexport const walletRevokeSession = {\n methodNames: ['wallet_revokeSession'],\n implementation: walletRevokeSessionHandler,\n hookNames: {\n revokePermissionForOrigin: true,\n updateCaveat: true,\n getCaveatForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-revokeSession.cjs","sourceRoot":"","sources":["../../src/handlers/wallet-revokeSession.ts"],"names":[],"mappings":";;;AAAA,mFAK6C;AAK7C,2EAIyC;AACzC,qDAAiD;AACjD,2CAIyB;AAIzB;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IACE,CAAC,IAAA,gBAAQ,EAAC,KAAK,CAAC;QAChB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QAClB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAC9B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO;QACL,gDAAwB,CAAC,IAAI;QAC7B,mDAA2B,CAAC,IAAI;KACjC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wBAAwB,CAC/B,MAAgB,EAChB,KAA+B;IAE/B,IAAI,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAC/C,yDAA6B,EAC7B,4CAAgB,CACjB,CAAC,KAAK,CAAC;IAER,KAAK,MAAM,WAAW,IAAI,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,gDAAoB,CAAC,4CAAgB,CAAC,CAAC,WAAW,CAC/D,kBAAkB,EAClB,WAAW,CACZ,CAAC;QAEF,0HAA0H;QAC1H,IAAI,MAAM,CAAC,SAAS,KAAK,8CAAsB,CAAC,IAAI,EAAE,CAAC;YACrD,SAAS;QACX,CAAC;QAED,kBAAkB,GAAG,MAAM,EAAE,KAAK,IAAI;YACpC,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,iBAAiB,EAAE,EAAE;YACrB,kBAAkB,EAAE,IAAI;SACzB,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAClB,IAAA,kEAAsC,EAAC,kBAAkB,CAAC,CAAC;IAE7D,+EAA+E;IAC/E,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,yBAAyB,CAAC,yDAA6B,CAAC,CAAC;IACjE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,YAAY,CAChB,yDAA6B,EAC7B,4CAAgB,EAChB,kBAAkB,CACnB,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,UAAU,0BAA0B,CACvC,OAGC,EACD,QAAwB,EACxB,KAAgC,EAChC,GAA6B,EAC7B,KAA+B;IAE/B,MAAM,EACJ,MAAM,EAAE,EAAE,MAAM,EAAE,GACnB,GAAG,OAAO,CAAC;IAEZ,IAAI,CAAC;QACH,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;YACnB,wBAAwB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,yBAAyB,CAAC,yDAA6B,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,sBAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AACY,QAAA,mBAAmB,GAAG;IACjC,WAAW,EAAE,CAAC,sBAAsB,CAAC;IACrC,cAAc,EAAE,0BAA0B;IAC1C,SAAS,EAAE;QACT,yBAAyB,EAAE,IAAI;QAC/B,YAAY,EAAE,IAAI;QAClB,kBAAkB,EAAE,IAAI;KACzB;CACF,CAAC","sourcesContent":["import {\n Caip25CaveatMutators,\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getCaipAccountIdsFromCaip25CaveatValue,\n} from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineNextCallback,\n JsonRpcEngineEndCallback,\n} from '@metamask/json-rpc-engine';\nimport {\n CaveatMutatorOperation,\n PermissionDoesNotExistError,\n UnrecognizedSubjectError,\n} from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n type JsonRpcSuccess,\n type JsonRpcRequest,\n isObject,\n} from '@metamask/utils';\n\nimport type { WalletRevokeSessionHooks } from './types';\n\n/**\n * Check whether the given error is a permission error.\n *\n * @param error - The error to check.\n * @returns Whether the error is a permission error.\n */\nfunction isPermissionError(error: unknown) {\n if (\n !isObject(error) ||\n !('name' in error) ||\n typeof error.name !== 'string'\n ) {\n return false;\n }\n\n return [\n UnrecognizedSubjectError.name,\n PermissionDoesNotExistError.name,\n ].includes(error.name);\n}\n\n/**\n * Revokes specific session scopes from an existing caveat.\n * Fully revokes permission if no accounts remain permitted after iterating through scopes.\n *\n * @param scopes - Array of scope strings to remove from the caveat.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n */\nfunction partialRevokePermissions(\n scopes: string[],\n hooks: WalletRevokeSessionHooks,\n) {\n let updatedCaveatValue = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n ).value;\n\n for (const scopeString of scopes) {\n const result = Caip25CaveatMutators[Caip25CaveatType].removeScope(\n updatedCaveatValue,\n scopeString,\n );\n\n // If operation is a Noop, it means a scope was passed that was not present in the permission, so we proceed with the loop\n if (result.operation === CaveatMutatorOperation.Noop) {\n continue;\n }\n\n updatedCaveatValue = result?.value ?? {\n requiredScopes: {},\n optionalScopes: {},\n sessionProperties: {},\n isMultichainOrigin: true,\n };\n }\n\n const caipAccountIds =\n getCaipAccountIdsFromCaip25CaveatValue(updatedCaveatValue);\n\n // We fully revoke permission if no accounts are left after scope removal loop.\n if (!caipAccountIds.length) {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n } else {\n hooks.updateCaveat(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n updatedCaveatValue,\n );\n }\n}\n\n/**\n * Handler for the `wallet_revokeSession` RPC method as specified by [CAIP-285](https://chainagnostic.org/CAIPs/caip-285).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead revokes the singular session for the origin if available. Additionally,\n * the handler also does not return an error if there is currently no active session and instead\n * returns true which is the same result returned if an active session was actually revoked.\n *\n * @param request - The JSON-RPC request object. Unused.\n * @param response - The JSON-RPC response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end callback function.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n * @returns Nothing.\n */\nasync function walletRevokeSessionHandler(\n request: JsonRpcRequest & {\n origin: string;\n params: { scopes?: string[] };\n },\n response: JsonRpcSuccess,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: WalletRevokeSessionHooks,\n) {\n const {\n params: { scopes },\n } = request;\n\n try {\n if (scopes?.length) {\n partialRevokePermissions(scopes, hooks);\n } else {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n }\n } catch (err) {\n if (!isPermissionError(err)) {\n console.error(err);\n return end(rpcErrors.internal());\n }\n }\n\n response.result = true;\n return end();\n}\nexport const walletRevokeSession = {\n methodNames: ['wallet_revokeSession'],\n implementation: walletRevokeSessionHandler,\n hookNames: {\n revokePermissionForOrigin: true,\n updateCaveat: true,\n getCaveatForOrigin: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"wallet-revokeSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-revokeSession.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,6BAA6B,EAC7B,sCAAsC,EACvC,4CAA4C;AAK7C,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,wBAAwB,EACzB,wCAAwC;AACzC,OAAO,EAAE,SAAS,EAAE,6BAA6B;AACjD,OAAO,EAGL,QAAQ,EACT,wBAAwB;AAIzB;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,KAAc;IACvC,IACE,CAAC,QAAQ,CAAC,KAAK,CAAC;QAChB,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC;QAClB,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAC9B;QACA,OAAO,KAAK,CAAC;KACd;IAED,OAAO;QACL,wBAAwB,CAAC,IAAI;QAC7B,2BAA2B,CAAC,IAAI;KACjC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,wBAAwB,CAC/B,MAAgB,EAChB,KAA+B;IAE/B,IAAI,kBAAkB,GAAG,KAAK,CAAC,kBAAkB,CAC/C,6BAA6B,EAC7B,gBAAgB,CACjB,CAAC,KAAK,CAAC;IAER,KAAK,MAAM,WAAW,IAAI,MAAM,EAAE;QAChC,MAAM,MAAM,GAAG,oBAAoB,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAC/D,kBAAkB,EAClB,WAAW,CACZ,CAAC;QAEF,0HAA0H;QAC1H,IAAI,MAAM,CAAC,SAAS,KAAK,sBAAsB,CAAC,IAAI,EAAE;YACpD,SAAS;SACV;QAED,kBAAkB,GAAG,MAAM,EAAE,KAAK,IAAI;YACpC,cAAc,EAAE,EAAE;YAClB,cAAc,EAAE,EAAE;YAClB,iBAAiB,EAAE,EAAE;YACrB,kBAAkB,EAAE,IAAI;SACzB,CAAC;KACH;IAED,MAAM,cAAc,GAClB,sCAAsC,CAAC,kBAAkB,CAAC,CAAC;IAE7D,+EAA+E;IAC/E,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QAC1B,KAAK,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,CAAC;KAChE;SAAM;QACL,KAAK,CAAC,YAAY,CAChB,6BAA6B,EAC7B,gBAAgB,EAChB,kBAAkB,CACnB,CAAC;KACH;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,KAAK,UAAU,0BAA0B,CACvC,OAGC,EACD,QAAwB,EACxB,KAAgC,EAChC,GAA6B,EAC7B,KAA+B;IAE/B,MAAM,EACJ,MAAM,EAAE,EAAE,MAAM,EAAE,GACnB,GAAG,OAAO,CAAC;IAEZ,IAAI;QACF,IAAI,MAAM,EAAE,MAAM,EAAE;YAClB,wBAAwB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;SACzC;aAAM;YACL,KAAK,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,CAAC;SAChE;KACF;IAAC,OAAO,GAAG,EAAE;QACZ,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE;YAC3B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;SAClC;KACF;IAED,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AACD,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,WAAW,EAAE,CAAC,sBAAsB,CAAC;IACrC,cAAc,EAAE,0BAA0B;IAC1C,SAAS,EAAE;QACT,yBAAyB,EAAE,IAAI;QAC/B,YAAY,EAAE,IAAI;QAClB,kBAAkB,EAAE,IAAI;KACzB;CACF,CAAC","sourcesContent":["import {\n Caip25CaveatMutators,\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getCaipAccountIdsFromCaip25CaveatValue,\n} from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineNextCallback,\n JsonRpcEngineEndCallback,\n} from '@metamask/json-rpc-engine';\nimport {\n CaveatMutatorOperation,\n PermissionDoesNotExistError,\n UnrecognizedSubjectError,\n} from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n type JsonRpcSuccess,\n type JsonRpcRequest,\n isObject,\n} from '@metamask/utils';\n\nimport type { WalletRevokeSessionHooks } from './types';\n\n/**\n * Check whether the given error is a permission error.\n *\n * @param error - The error to check.\n * @returns Whether the error is a permission error.\n */\nfunction isPermissionError(error: unknown) {\n if (\n !isObject(error) ||\n !('name' in error) ||\n typeof error.name !== 'string'\n ) {\n return false;\n }\n\n return [\n UnrecognizedSubjectError.name,\n PermissionDoesNotExistError.name,\n ].includes(error.name);\n}\n\n/**\n * Revokes specific session scopes from an existing caveat.\n * Fully revokes permission if no accounts remain permitted after iterating through scopes.\n *\n * @param scopes - Array of scope strings to remove from the caveat.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n */\nfunction partialRevokePermissions(\n scopes: string[],\n hooks: WalletRevokeSessionHooks,\n) {\n let updatedCaveatValue = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n ).value;\n\n for (const scopeString of scopes) {\n const result = Caip25CaveatMutators[Caip25CaveatType].removeScope(\n updatedCaveatValue,\n scopeString,\n );\n\n // If operation is a Noop, it means a scope was passed that was not present in the permission, so we proceed with the loop\n if (result.operation === CaveatMutatorOperation.Noop) {\n continue;\n }\n\n updatedCaveatValue = result?.value ?? {\n requiredScopes: {},\n optionalScopes: {},\n sessionProperties: {},\n isMultichainOrigin: true,\n };\n }\n\n const caipAccountIds =\n getCaipAccountIdsFromCaip25CaveatValue(updatedCaveatValue);\n\n // We fully revoke permission if no accounts are left after scope removal loop.\n if (!caipAccountIds.length) {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n } else {\n hooks.updateCaveat(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n updatedCaveatValue,\n );\n }\n}\n\n/**\n * Handler for the `wallet_revokeSession` RPC method as specified by [CAIP-285](https://chainagnostic.org/CAIPs/caip-285).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead revokes the singular session for the origin if available. Additionally,\n * the handler also does not return an error if there is currently no active session and instead\n * returns true which is the same result returned if an active session was actually revoked.\n *\n * @param request - The JSON-RPC request object. Unused.\n * @param response - The JSON-RPC response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end callback function.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n * @returns Nothing.\n */\nasync function walletRevokeSessionHandler(\n request: JsonRpcRequest & {\n origin: string;\n params: { scopes?: string[] };\n },\n response: JsonRpcSuccess,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: WalletRevokeSessionHooks,\n) {\n const {\n params: { scopes },\n } = request;\n\n try {\n if (scopes?.length) {\n partialRevokePermissions(scopes, hooks);\n } else {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n }\n } catch (err) {\n if (!isPermissionError(err)) {\n console.error(err);\n return end(rpcErrors.internal());\n }\n }\n\n response.result = true;\n return end();\n}\nexport const walletRevokeSession = {\n methodNames: ['wallet_revokeSession'],\n implementation: walletRevokeSessionHandler,\n hookNames: {\n revokePermissionForOrigin: true,\n updateCaveat: true,\n getCaveatForOrigin: true,\n },\n};\n"]}
1
+ {"version":3,"file":"wallet-revokeSession.mjs","sourceRoot":"","sources":["../../src/handlers/wallet-revokeSession.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Caip25CaveatMutators,\n Caip25CaveatType,\n Caip25EndowmentPermissionName,\n getCaipAccountIdsFromCaip25CaveatValue,\n} from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineNextCallback,\n JsonRpcEngineEndCallback,\n} from '@metamask/json-rpc-engine';\nimport {\n CaveatMutatorOperation,\n PermissionDoesNotExistError,\n UnrecognizedSubjectError,\n} from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport {\n type JsonRpcSuccess,\n type JsonRpcRequest,\n isObject,\n} from '@metamask/utils';\n\nimport type { WalletRevokeSessionHooks } from './types';\n\n/**\n * Check whether the given error is a permission error.\n *\n * @param error - The error to check.\n * @returns Whether the error is a permission error.\n */\nfunction isPermissionError(error: unknown) {\n if (\n !isObject(error) ||\n !('name' in error) ||\n typeof error.name !== 'string'\n ) {\n return false;\n }\n\n return [\n UnrecognizedSubjectError.name,\n PermissionDoesNotExistError.name,\n ].includes(error.name);\n}\n\n/**\n * Revokes specific session scopes from an existing caveat.\n * Fully revokes permission if no accounts remain permitted after iterating through scopes.\n *\n * @param scopes - Array of scope strings to remove from the caveat.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n */\nfunction partialRevokePermissions(\n scopes: string[],\n hooks: WalletRevokeSessionHooks,\n) {\n let updatedCaveatValue = hooks.getCaveatForOrigin(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n ).value;\n\n for (const scopeString of scopes) {\n const result = Caip25CaveatMutators[Caip25CaveatType].removeScope(\n updatedCaveatValue,\n scopeString,\n );\n\n // If operation is a Noop, it means a scope was passed that was not present in the permission, so we proceed with the loop\n if (result.operation === CaveatMutatorOperation.Noop) {\n continue;\n }\n\n updatedCaveatValue = result?.value ?? {\n requiredScopes: {},\n optionalScopes: {},\n sessionProperties: {},\n isMultichainOrigin: true,\n };\n }\n\n const caipAccountIds =\n getCaipAccountIdsFromCaip25CaveatValue(updatedCaveatValue);\n\n // We fully revoke permission if no accounts are left after scope removal loop.\n if (!caipAccountIds.length) {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n } else {\n hooks.updateCaveat(\n Caip25EndowmentPermissionName,\n Caip25CaveatType,\n updatedCaveatValue,\n );\n }\n}\n\n/**\n * Handler for the `wallet_revokeSession` RPC method as specified by [CAIP-285](https://chainagnostic.org/CAIPs/caip-285).\n * The implementation below deviates from the linked spec in that it ignores the `sessionId` param\n * and instead revokes the singular session for the origin if available. Additionally,\n * the handler also does not return an error if there is currently no active session and instead\n * returns true which is the same result returned if an active session was actually revoked.\n *\n * @param request - The JSON-RPC request object. Unused.\n * @param response - The JSON-RPC response object.\n * @param _next - The next middleware function. Unused.\n * @param end - The end callback function.\n * @param hooks - The hooks object.\n * @param hooks.revokePermissionForOrigin - The hook for revoking a permission for an origin function.\n * @param hooks.updateCaveat - The hook used to conditionally update the caveat rather than fully revoke the permission.\n * @param hooks.getCaveatForOrigin - The hook to fetch an existing caveat for the origin of the request.\n * @returns Nothing.\n */\nasync function walletRevokeSessionHandler(\n request: JsonRpcRequest & {\n origin: string;\n params: { scopes?: string[] };\n },\n response: JsonRpcSuccess,\n _next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n hooks: WalletRevokeSessionHooks,\n) {\n const {\n params: { scopes },\n } = request;\n\n try {\n if (scopes?.length) {\n partialRevokePermissions(scopes, hooks);\n } else {\n hooks.revokePermissionForOrigin(Caip25EndowmentPermissionName);\n }\n } catch (err) {\n if (!isPermissionError(err)) {\n console.error(err);\n return end(rpcErrors.internal());\n }\n }\n\n response.result = true;\n return end();\n}\nexport const walletRevokeSession = {\n methodNames: ['wallet_revokeSession'],\n implementation: walletRevokeSessionHandler,\n hookNames: {\n revokePermissionForOrigin: true,\n updateCaveat: true,\n getCaveatForOrigin: true,\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainMiddlewareManager.cjs","sourceRoot":"","sources":["../../src/middlewares/MultichainMiddlewareManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';\n\nexport type ExtendedJsonRpcMiddleware = {\n (\n req: JsonRpcRequest & { scope: string },\n res: PendingJsonRpcResponse,\n next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n ): void;\n destroy?: () => void | Promise<void>;\n};\n\ntype MiddlewareKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype MiddlewareEntry = MiddlewareKey & {\n middleware: ExtendedJsonRpcMiddleware;\n};\n\n// Methods related to eth_subscriptions\nconst SubscriptionMethods = ['eth_subscribe', 'eth_unsubscribe'];\n\n/**\n * A helper that facilates registering and calling of provided middleware instances\n * in the RPC pipeline based on the incoming request's scope, origin, and tabId.\n * The core purpose of this class is to enable and manage multichain subscriptions\n * (i.e. eth_subscribe called accross different chains and domains).\n *\n * Note that only one middleware instance can be registered per scope, origin, tabId key.\n */\nexport class MultichainMiddlewareManager {\n #middlewares: MiddlewareEntry[] = [];\n\n #getMiddlewareEntry({\n scope,\n origin,\n tabId,\n }: MiddlewareKey): MiddlewareEntry | undefined {\n return this.#middlewares.find((middlewareEntry) => {\n return (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n );\n });\n }\n\n #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareEntry) {\n this.#middlewares = this.#middlewares.filter((middlewareEntry) => {\n return (\n middlewareEntry.scope !== scope ||\n middlewareEntry.origin !== origin ||\n middlewareEntry.tabId !== tabId\n );\n });\n }\n\n addMiddleware(middlewareEntry: MiddlewareEntry) {\n const { scope, origin, tabId } = middlewareEntry;\n if (!this.#getMiddlewareEntry({ scope, origin, tabId })) {\n this.#middlewares.push(middlewareEntry);\n }\n }\n\n #removeMiddleware(middlewareEntry: MiddlewareEntry) {\n // When the destroy function on the middleware is async,\n // we don't need to wait for it complete\n Promise.resolve(middlewareEntry.middleware.destroy?.()).catch(() => {\n // do nothing\n });\n\n this.#removeMiddlewareEntry(middlewareEntry);\n }\n\n removeMiddlewareByScope(scope: ExternalScopeString) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (middlewareEntry.scope === scope) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n generateMultichainMiddlewareForOriginAndTabId(\n origin: string,\n tabId?: number,\n ) {\n const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => {\n const { scope } = req;\n const middlewareEntry = this.#getMiddlewareEntry({\n scope,\n origin,\n tabId,\n });\n\n if (SubscriptionMethods.includes(req.method)) {\n if (middlewareEntry) {\n middlewareEntry.middleware(req, res, next, end);\n } else {\n // TODO: Temporary safety guard to prevent requests with these methods\n // from being forwarded to the RPC endpoint even though this scenario\n // should not be possible.\n return end(rpcErrors.methodNotFound());\n }\n } else {\n return next();\n }\n return undefined;\n };\n middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind(\n this,\n origin,\n tabId,\n );\n\n return middleware;\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainMiddlewareManager.cjs","sourceRoot":"","sources":["../../src/middlewares/MultichainMiddlewareManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';\n\nexport type ExtendedJsonRpcMiddleware = {\n (\n req: JsonRpcRequest & { scope: string },\n res: PendingJsonRpcResponse,\n next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n ): void;\n destroy?: () => void | Promise<void>;\n};\n\ntype MiddlewareKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype MiddlewareEntry = MiddlewareKey & {\n middleware: ExtendedJsonRpcMiddleware;\n};\n\n// Methods related to eth_subscriptions\nconst SubscriptionMethods = ['eth_subscribe', 'eth_unsubscribe'];\n\n/**\n * A helper that facilates registering and calling of provided middleware instances\n * in the RPC pipeline based on the incoming request's scope, origin, and tabId.\n * The core purpose of this class is to enable and manage multichain subscriptions\n * (i.e. eth_subscribe called accross different chains and domains).\n *\n * Note that only one middleware instance can be registered per scope, origin, tabId key.\n */\nexport class MultichainMiddlewareManager {\n #middlewares: MiddlewareEntry[] = [];\n\n #getMiddlewareEntry({\n scope,\n origin,\n tabId,\n }: MiddlewareKey): MiddlewareEntry | undefined {\n return this.#middlewares.find((middlewareEntry) => {\n return (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n );\n });\n }\n\n #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareEntry) {\n this.#middlewares = this.#middlewares.filter((middlewareEntry) => {\n return (\n middlewareEntry.scope !== scope ||\n middlewareEntry.origin !== origin ||\n middlewareEntry.tabId !== tabId\n );\n });\n }\n\n addMiddleware(middlewareEntry: MiddlewareEntry) {\n const { scope, origin, tabId } = middlewareEntry;\n if (!this.#getMiddlewareEntry({ scope, origin, tabId })) {\n this.#middlewares.push(middlewareEntry);\n }\n }\n\n #removeMiddleware(middlewareEntry: MiddlewareEntry) {\n // When the destroy function on the middleware is async,\n // we don't need to wait for it complete\n Promise.resolve(middlewareEntry.middleware.destroy?.()).catch(() => {\n // do nothing\n });\n\n this.#removeMiddlewareEntry(middlewareEntry);\n }\n\n removeMiddlewareByScope(scope: ExternalScopeString) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (middlewareEntry.scope === scope) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n generateMultichainMiddlewareForOriginAndTabId(\n origin: string,\n tabId?: number,\n ) {\n const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => {\n const { scope } = req;\n const middlewareEntry = this.#getMiddlewareEntry({\n scope,\n origin,\n tabId,\n });\n\n if (SubscriptionMethods.includes(req.method)) {\n if (middlewareEntry) {\n middlewareEntry.middleware(req, res, next, end);\n } else {\n // TODO: Temporary safety guard to prevent requests with these methods\n // from being forwarded to the RPC endpoint even though this scenario\n // should not be possible.\n return end(rpcErrors.methodNotFound());\n }\n } else {\n return next();\n }\n return undefined;\n };\n middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind(\n this,\n origin,\n tabId,\n );\n\n return middleware;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainMiddlewareManager.mjs","sourceRoot":"","sources":["../../src/middlewares/MultichainMiddlewareManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';\n\nexport type ExtendedJsonRpcMiddleware = {\n (\n req: JsonRpcRequest & { scope: string },\n res: PendingJsonRpcResponse,\n next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n ): void;\n destroy?: () => void | Promise<void>;\n};\n\ntype MiddlewareKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype MiddlewareEntry = MiddlewareKey & {\n middleware: ExtendedJsonRpcMiddleware;\n};\n\n// Methods related to eth_subscriptions\nconst SubscriptionMethods = ['eth_subscribe', 'eth_unsubscribe'];\n\n/**\n * A helper that facilates registering and calling of provided middleware instances\n * in the RPC pipeline based on the incoming request's scope, origin, and tabId.\n * The core purpose of this class is to enable and manage multichain subscriptions\n * (i.e. eth_subscribe called accross different chains and domains).\n *\n * Note that only one middleware instance can be registered per scope, origin, tabId key.\n */\nexport class MultichainMiddlewareManager {\n #middlewares: MiddlewareEntry[] = [];\n\n #getMiddlewareEntry({\n scope,\n origin,\n tabId,\n }: MiddlewareKey): MiddlewareEntry | undefined {\n return this.#middlewares.find((middlewareEntry) => {\n return (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n );\n });\n }\n\n #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareEntry) {\n this.#middlewares = this.#middlewares.filter((middlewareEntry) => {\n return (\n middlewareEntry.scope !== scope ||\n middlewareEntry.origin !== origin ||\n middlewareEntry.tabId !== tabId\n );\n });\n }\n\n addMiddleware(middlewareEntry: MiddlewareEntry) {\n const { scope, origin, tabId } = middlewareEntry;\n if (!this.#getMiddlewareEntry({ scope, origin, tabId })) {\n this.#middlewares.push(middlewareEntry);\n }\n }\n\n #removeMiddleware(middlewareEntry: MiddlewareEntry) {\n // When the destroy function on the middleware is async,\n // we don't need to wait for it complete\n Promise.resolve(middlewareEntry.middleware.destroy?.()).catch(() => {\n // do nothing\n });\n\n this.#removeMiddlewareEntry(middlewareEntry);\n }\n\n removeMiddlewareByScope(scope: ExternalScopeString) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (middlewareEntry.scope === scope) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n generateMultichainMiddlewareForOriginAndTabId(\n origin: string,\n tabId?: number,\n ) {\n const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => {\n const { scope } = req;\n const middlewareEntry = this.#getMiddlewareEntry({\n scope,\n origin,\n tabId,\n });\n\n if (SubscriptionMethods.includes(req.method)) {\n if (middlewareEntry) {\n middlewareEntry.middleware(req, res, next, end);\n } else {\n // TODO: Temporary safety guard to prevent requests with these methods\n // from being forwarded to the RPC endpoint even though this scenario\n // should not be possible.\n return end(rpcErrors.methodNotFound());\n }\n } else {\n return next();\n }\n return undefined;\n };\n middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind(\n this,\n origin,\n tabId,\n );\n\n return middleware;\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainMiddlewareManager.mjs","sourceRoot":"","sources":["../../src/middlewares/MultichainMiddlewareManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport type {\n JsonRpcEngineEndCallback,\n JsonRpcEngineNextCallback,\n} from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { JsonRpcRequest, PendingJsonRpcResponse } from '@metamask/utils';\n\nexport type ExtendedJsonRpcMiddleware = {\n (\n req: JsonRpcRequest & { scope: string },\n res: PendingJsonRpcResponse,\n next: JsonRpcEngineNextCallback,\n end: JsonRpcEngineEndCallback,\n ): void;\n destroy?: () => void | Promise<void>;\n};\n\ntype MiddlewareKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype MiddlewareEntry = MiddlewareKey & {\n middleware: ExtendedJsonRpcMiddleware;\n};\n\n// Methods related to eth_subscriptions\nconst SubscriptionMethods = ['eth_subscribe', 'eth_unsubscribe'];\n\n/**\n * A helper that facilates registering and calling of provided middleware instances\n * in the RPC pipeline based on the incoming request's scope, origin, and tabId.\n * The core purpose of this class is to enable and manage multichain subscriptions\n * (i.e. eth_subscribe called accross different chains and domains).\n *\n * Note that only one middleware instance can be registered per scope, origin, tabId key.\n */\nexport class MultichainMiddlewareManager {\n #middlewares: MiddlewareEntry[] = [];\n\n #getMiddlewareEntry({\n scope,\n origin,\n tabId,\n }: MiddlewareKey): MiddlewareEntry | undefined {\n return this.#middlewares.find((middlewareEntry) => {\n return (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n );\n });\n }\n\n #removeMiddlewareEntry({ scope, origin, tabId }: MiddlewareEntry) {\n this.#middlewares = this.#middlewares.filter((middlewareEntry) => {\n return (\n middlewareEntry.scope !== scope ||\n middlewareEntry.origin !== origin ||\n middlewareEntry.tabId !== tabId\n );\n });\n }\n\n addMiddleware(middlewareEntry: MiddlewareEntry) {\n const { scope, origin, tabId } = middlewareEntry;\n if (!this.#getMiddlewareEntry({ scope, origin, tabId })) {\n this.#middlewares.push(middlewareEntry);\n }\n }\n\n #removeMiddleware(middlewareEntry: MiddlewareEntry) {\n // When the destroy function on the middleware is async,\n // we don't need to wait for it complete\n Promise.resolve(middlewareEntry.middleware.destroy?.()).catch(() => {\n // do nothing\n });\n\n this.#removeMiddlewareEntry(middlewareEntry);\n }\n\n removeMiddlewareByScope(scope: ExternalScopeString) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (middlewareEntry.scope === scope) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.scope === scope &&\n middlewareEntry.origin === origin\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n removeMiddlewareByOriginAndTabId(origin: string, tabId?: number) {\n this.#middlewares.forEach((middlewareEntry) => {\n if (\n middlewareEntry.origin === origin &&\n middlewareEntry.tabId === tabId\n ) {\n this.#removeMiddleware(middlewareEntry);\n }\n });\n }\n\n generateMultichainMiddlewareForOriginAndTabId(\n origin: string,\n tabId?: number,\n ) {\n const middleware: ExtendedJsonRpcMiddleware = (req, res, next, end) => {\n const { scope } = req;\n const middlewareEntry = this.#getMiddlewareEntry({\n scope,\n origin,\n tabId,\n });\n\n if (SubscriptionMethods.includes(req.method)) {\n if (middlewareEntry) {\n middlewareEntry.middleware(req, res, next, end);\n } else {\n // TODO: Temporary safety guard to prevent requests with these methods\n // from being forwarded to the RPC endpoint even though this scenario\n // should not be possible.\n return end(rpcErrors.methodNotFound());\n }\n } else {\n return next();\n }\n return undefined;\n };\n middleware.destroy = this.removeMiddlewareByOriginAndTabId.bind(\n this,\n origin,\n tabId,\n );\n\n return middleware;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainSubscriptionManager.cjs","sourceRoot":"","sources":["../../src/middlewares/MultichainSubscriptionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport { toHex } from '@metamask/controller-utils';\nimport createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager';\nimport type { NetworkController } from '@metamask/network-controller';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\n\nimport type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager';\nimport { MultichainApiNotifications } from '../handlers/types';\n\nexport type SubscriptionManager = {\n events: SafeEventEmitter;\n destroy?: () => void;\n middleware: ExtendedJsonRpcMiddleware;\n};\n\ntype SubscriptionNotificationEvent = {\n jsonrpc: '2.0';\n method: 'eth_subscription';\n params: {\n subscription: Hex;\n result: unknown;\n };\n};\n\ntype SubscriptionKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype SubscriptionEntry = SubscriptionKey & {\n subscriptionManager: SubscriptionManager;\n};\n\ntype MultichainSubscriptionManagerOptions = {\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n};\n\n/**\n * A helper that facilates the lifecycle of a SubscriptionManager instance that\n * is meant to handle subscriptons for only one specific scope, origin, and tabId combination.\n */\nexport class MultichainSubscriptionManager extends SafeEventEmitter {\n readonly #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n\n readonly #getNetworkClientById: NetworkController['getNetworkClientById'];\n\n #subscriptions: SubscriptionEntry[] = [];\n\n /**\n * Construct a MultichainSubscriptionManager.\n *\n * @param options - The controller options.\n * @param options.findNetworkClientIdByChainId - The hook to get the networkClientId from a chainId.\n * @param options.getNetworkClientById - The hook to get the network client instance by its networkClientId.\n */\n constructor(options: MultichainSubscriptionManagerOptions) {\n super();\n this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId;\n this.#getNetworkClientById = options.getNetworkClientById;\n }\n\n notify(\n { scope, origin, tabId }: SubscriptionKey,\n { method, params }: SubscriptionNotificationEvent,\n ) {\n this.emit('notification', origin, tabId, {\n method: MultichainApiNotifications.walletNotify,\n params: {\n scope,\n notification: { method, params },\n },\n });\n }\n\n #getSubscriptionEntry({\n scope,\n origin,\n tabId,\n }: SubscriptionKey): SubscriptionEntry | undefined {\n return this.#subscriptions.find((subscriptionEntry) => {\n return (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n );\n });\n }\n\n #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionEntry) {\n this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => {\n return (\n subscriptionEntry.scope !== scope ||\n subscriptionEntry.origin !== origin ||\n subscriptionEntry.tabId !== tabId\n );\n });\n }\n\n subscribe(subscriptionKey: SubscriptionKey) {\n const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey);\n if (subscriptionEntry) {\n return subscriptionEntry.subscriptionManager;\n }\n\n const networkClientId = this.#findNetworkClientIdByChainId(\n toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference),\n );\n const networkClient = this.#getNetworkClientById(networkClientId);\n const subscriptionManager = createSubscriptionManager({\n blockTracker: networkClient.blockTracker,\n provider: networkClient.provider,\n });\n\n subscriptionManager.events.on(\n 'notification',\n (message: SubscriptionNotificationEvent) => {\n this.notify(subscriptionKey, message);\n },\n );\n\n const newSubscriptionManagerEntry = {\n ...subscriptionKey,\n subscriptionManager,\n };\n subscriptionManager.destroy = subscriptionManager.middleware.destroy;\n subscriptionManager.middleware.destroy = this.#unsubscribe.bind(\n this,\n newSubscriptionManagerEntry,\n );\n\n this.#subscriptions.push(newSubscriptionManagerEntry);\n\n return subscriptionManager;\n }\n\n #unsubscribe(subscriptionEntry: SubscriptionEntry) {\n subscriptionEntry.subscriptionManager.destroy?.();\n\n this.#removeSubscriptionEntry(subscriptionEntry);\n }\n\n unsubscribeByScope(scope: ExternalScopeString) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (subscriptionEntry.scope === scope) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByOriginAndTabId(origin: string, tabId?: number) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainSubscriptionManager.cjs","sourceRoot":"","sources":["../../src/middlewares/MultichainSubscriptionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport { toHex } from '@metamask/controller-utils';\nimport createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager';\nimport type { NetworkController } from '@metamask/network-controller';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\n\nimport type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager';\nimport { MultichainApiNotifications } from '../handlers/types';\n\nexport type SubscriptionManager = {\n events: SafeEventEmitter;\n destroy?: () => void;\n middleware: ExtendedJsonRpcMiddleware;\n};\n\ntype SubscriptionNotificationEvent = {\n jsonrpc: '2.0';\n method: 'eth_subscription';\n params: {\n subscription: Hex;\n result: unknown;\n };\n};\n\ntype SubscriptionKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype SubscriptionEntry = SubscriptionKey & {\n subscriptionManager: SubscriptionManager;\n};\n\ntype MultichainSubscriptionManagerOptions = {\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n};\n\n/**\n * A helper that facilates the lifecycle of a SubscriptionManager instance that\n * is meant to handle subscriptons for only one specific scope, origin, and tabId combination.\n */\nexport class MultichainSubscriptionManager extends SafeEventEmitter {\n readonly #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n\n readonly #getNetworkClientById: NetworkController['getNetworkClientById'];\n\n #subscriptions: SubscriptionEntry[] = [];\n\n /**\n * Construct a MultichainSubscriptionManager.\n *\n * @param options - The controller options.\n * @param options.findNetworkClientIdByChainId - The hook to get the networkClientId from a chainId.\n * @param options.getNetworkClientById - The hook to get the network client instance by its networkClientId.\n */\n constructor(options: MultichainSubscriptionManagerOptions) {\n super();\n this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId;\n this.#getNetworkClientById = options.getNetworkClientById;\n }\n\n notify(\n { scope, origin, tabId }: SubscriptionKey,\n { method, params }: SubscriptionNotificationEvent,\n ) {\n this.emit('notification', origin, tabId, {\n method: MultichainApiNotifications.walletNotify,\n params: {\n scope,\n notification: { method, params },\n },\n });\n }\n\n #getSubscriptionEntry({\n scope,\n origin,\n tabId,\n }: SubscriptionKey): SubscriptionEntry | undefined {\n return this.#subscriptions.find((subscriptionEntry) => {\n return (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n );\n });\n }\n\n #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionEntry) {\n this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => {\n return (\n subscriptionEntry.scope !== scope ||\n subscriptionEntry.origin !== origin ||\n subscriptionEntry.tabId !== tabId\n );\n });\n }\n\n subscribe(subscriptionKey: SubscriptionKey) {\n const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey);\n if (subscriptionEntry) {\n return subscriptionEntry.subscriptionManager;\n }\n\n const networkClientId = this.#findNetworkClientIdByChainId(\n toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference),\n );\n const networkClient = this.#getNetworkClientById(networkClientId);\n const subscriptionManager = createSubscriptionManager({\n blockTracker: networkClient.blockTracker,\n provider: networkClient.provider,\n });\n\n subscriptionManager.events.on(\n 'notification',\n (message: SubscriptionNotificationEvent) => {\n this.notify(subscriptionKey, message);\n },\n );\n\n const newSubscriptionManagerEntry = {\n ...subscriptionKey,\n subscriptionManager,\n };\n subscriptionManager.destroy = subscriptionManager.middleware.destroy;\n subscriptionManager.middleware.destroy = this.#unsubscribe.bind(\n this,\n newSubscriptionManagerEntry,\n );\n\n this.#subscriptions.push(newSubscriptionManagerEntry);\n\n return subscriptionManager;\n }\n\n #unsubscribe(subscriptionEntry: SubscriptionEntry) {\n subscriptionEntry.subscriptionManager.destroy?.();\n\n this.#removeSubscriptionEntry(subscriptionEntry);\n }\n\n unsubscribeByScope(scope: ExternalScopeString) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (subscriptionEntry.scope === scope) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByOriginAndTabId(origin: string, tabId?: number) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"MultichainSubscriptionManager.mjs","sourceRoot":"","sources":["../../src/middlewares/MultichainSubscriptionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport { toHex } from '@metamask/controller-utils';\nimport createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager';\nimport type { NetworkController } from '@metamask/network-controller';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\n\nimport type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager';\nimport { MultichainApiNotifications } from '../handlers/types';\n\nexport type SubscriptionManager = {\n events: SafeEventEmitter;\n destroy?: () => void;\n middleware: ExtendedJsonRpcMiddleware;\n};\n\ntype SubscriptionNotificationEvent = {\n jsonrpc: '2.0';\n method: 'eth_subscription';\n params: {\n subscription: Hex;\n result: unknown;\n };\n};\n\ntype SubscriptionKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype SubscriptionEntry = SubscriptionKey & {\n subscriptionManager: SubscriptionManager;\n};\n\ntype MultichainSubscriptionManagerOptions = {\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n};\n\n/**\n * A helper that facilates the lifecycle of a SubscriptionManager instance that\n * is meant to handle subscriptons for only one specific scope, origin, and tabId combination.\n */\nexport class MultichainSubscriptionManager extends SafeEventEmitter {\n readonly #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n\n readonly #getNetworkClientById: NetworkController['getNetworkClientById'];\n\n #subscriptions: SubscriptionEntry[] = [];\n\n /**\n * Construct a MultichainSubscriptionManager.\n *\n * @param options - The controller options.\n * @param options.findNetworkClientIdByChainId - The hook to get the networkClientId from a chainId.\n * @param options.getNetworkClientById - The hook to get the network client instance by its networkClientId.\n */\n constructor(options: MultichainSubscriptionManagerOptions) {\n super();\n this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId;\n this.#getNetworkClientById = options.getNetworkClientById;\n }\n\n notify(\n { scope, origin, tabId }: SubscriptionKey,\n { method, params }: SubscriptionNotificationEvent,\n ) {\n this.emit('notification', origin, tabId, {\n method: MultichainApiNotifications.walletNotify,\n params: {\n scope,\n notification: { method, params },\n },\n });\n }\n\n #getSubscriptionEntry({\n scope,\n origin,\n tabId,\n }: SubscriptionKey): SubscriptionEntry | undefined {\n return this.#subscriptions.find((subscriptionEntry) => {\n return (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n );\n });\n }\n\n #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionEntry) {\n this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => {\n return (\n subscriptionEntry.scope !== scope ||\n subscriptionEntry.origin !== origin ||\n subscriptionEntry.tabId !== tabId\n );\n });\n }\n\n subscribe(subscriptionKey: SubscriptionKey) {\n const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey);\n if (subscriptionEntry) {\n return subscriptionEntry.subscriptionManager;\n }\n\n const networkClientId = this.#findNetworkClientIdByChainId(\n toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference),\n );\n const networkClient = this.#getNetworkClientById(networkClientId);\n const subscriptionManager = createSubscriptionManager({\n blockTracker: networkClient.blockTracker,\n provider: networkClient.provider,\n });\n\n subscriptionManager.events.on(\n 'notification',\n (message: SubscriptionNotificationEvent) => {\n this.notify(subscriptionKey, message);\n },\n );\n\n const newSubscriptionManagerEntry = {\n ...subscriptionKey,\n subscriptionManager,\n };\n subscriptionManager.destroy = subscriptionManager.middleware.destroy;\n subscriptionManager.middleware.destroy = this.#unsubscribe.bind(\n this,\n newSubscriptionManagerEntry,\n );\n\n this.#subscriptions.push(newSubscriptionManagerEntry);\n\n return subscriptionManager;\n }\n\n #unsubscribe(subscriptionEntry: SubscriptionEntry) {\n subscriptionEntry.subscriptionManager.destroy?.();\n\n this.#removeSubscriptionEntry(subscriptionEntry);\n }\n\n unsubscribeByScope(scope: ExternalScopeString) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (subscriptionEntry.scope === scope) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByOriginAndTabId(origin: string, tabId?: number) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n}\n"]}
1
+ {"version":3,"file":"MultichainSubscriptionManager.mjs","sourceRoot":"","sources":["../../src/middlewares/MultichainSubscriptionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExternalScopeString } from '@metamask/chain-agnostic-permission';\nimport { toHex } from '@metamask/controller-utils';\nimport createSubscriptionManager from '@metamask/eth-json-rpc-filters/subscriptionManager';\nimport type { NetworkController } from '@metamask/network-controller';\nimport SafeEventEmitter from '@metamask/safe-event-emitter';\nimport type { CaipChainId, Hex } from '@metamask/utils';\nimport { parseCaipChainId } from '@metamask/utils';\n\nimport type { ExtendedJsonRpcMiddleware } from './MultichainMiddlewareManager';\nimport { MultichainApiNotifications } from '../handlers/types';\n\nexport type SubscriptionManager = {\n events: SafeEventEmitter;\n destroy?: () => void;\n middleware: ExtendedJsonRpcMiddleware;\n};\n\ntype SubscriptionNotificationEvent = {\n jsonrpc: '2.0';\n method: 'eth_subscription';\n params: {\n subscription: Hex;\n result: unknown;\n };\n};\n\ntype SubscriptionKey = {\n scope: ExternalScopeString;\n origin: string;\n tabId?: number;\n};\ntype SubscriptionEntry = SubscriptionKey & {\n subscriptionManager: SubscriptionManager;\n};\n\ntype MultichainSubscriptionManagerOptions = {\n findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n getNetworkClientById: NetworkController['getNetworkClientById'];\n};\n\n/**\n * A helper that facilates the lifecycle of a SubscriptionManager instance that\n * is meant to handle subscriptons for only one specific scope, origin, and tabId combination.\n */\nexport class MultichainSubscriptionManager extends SafeEventEmitter {\n readonly #findNetworkClientIdByChainId: NetworkController['findNetworkClientIdByChainId'];\n\n readonly #getNetworkClientById: NetworkController['getNetworkClientById'];\n\n #subscriptions: SubscriptionEntry[] = [];\n\n /**\n * Construct a MultichainSubscriptionManager.\n *\n * @param options - The controller options.\n * @param options.findNetworkClientIdByChainId - The hook to get the networkClientId from a chainId.\n * @param options.getNetworkClientById - The hook to get the network client instance by its networkClientId.\n */\n constructor(options: MultichainSubscriptionManagerOptions) {\n super();\n this.#findNetworkClientIdByChainId = options.findNetworkClientIdByChainId;\n this.#getNetworkClientById = options.getNetworkClientById;\n }\n\n notify(\n { scope, origin, tabId }: SubscriptionKey,\n { method, params }: SubscriptionNotificationEvent,\n ) {\n this.emit('notification', origin, tabId, {\n method: MultichainApiNotifications.walletNotify,\n params: {\n scope,\n notification: { method, params },\n },\n });\n }\n\n #getSubscriptionEntry({\n scope,\n origin,\n tabId,\n }: SubscriptionKey): SubscriptionEntry | undefined {\n return this.#subscriptions.find((subscriptionEntry) => {\n return (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n );\n });\n }\n\n #removeSubscriptionEntry({ scope, origin, tabId }: SubscriptionEntry) {\n this.#subscriptions = this.#subscriptions.filter((subscriptionEntry) => {\n return (\n subscriptionEntry.scope !== scope ||\n subscriptionEntry.origin !== origin ||\n subscriptionEntry.tabId !== tabId\n );\n });\n }\n\n subscribe(subscriptionKey: SubscriptionKey) {\n const subscriptionEntry = this.#getSubscriptionEntry(subscriptionKey);\n if (subscriptionEntry) {\n return subscriptionEntry.subscriptionManager;\n }\n\n const networkClientId = this.#findNetworkClientIdByChainId(\n toHex(parseCaipChainId(subscriptionKey.scope as CaipChainId).reference),\n );\n const networkClient = this.#getNetworkClientById(networkClientId);\n const subscriptionManager = createSubscriptionManager({\n blockTracker: networkClient.blockTracker,\n provider: networkClient.provider,\n });\n\n subscriptionManager.events.on(\n 'notification',\n (message: SubscriptionNotificationEvent) => {\n this.notify(subscriptionKey, message);\n },\n );\n\n const newSubscriptionManagerEntry = {\n ...subscriptionKey,\n subscriptionManager,\n };\n subscriptionManager.destroy = subscriptionManager.middleware.destroy;\n subscriptionManager.middleware.destroy = this.#unsubscribe.bind(\n this,\n newSubscriptionManagerEntry,\n );\n\n this.#subscriptions.push(newSubscriptionManagerEntry);\n\n return subscriptionManager;\n }\n\n #unsubscribe(subscriptionEntry: SubscriptionEntry) {\n subscriptionEntry.subscriptionManager.destroy?.();\n\n this.#removeSubscriptionEntry(subscriptionEntry);\n }\n\n unsubscribeByScope(scope: ExternalScopeString) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (subscriptionEntry.scope === scope) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByScopeAndOrigin(scope: ExternalScopeString, origin: string) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.scope === scope &&\n subscriptionEntry.origin === origin\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n\n unsubscribeByOriginAndTabId(origin: string, tabId?: number) {\n this.#subscriptions.forEach((subscriptionEntry) => {\n if (\n subscriptionEntry.origin === origin &&\n subscriptionEntry.tabId === tabId\n ) {\n this.#unsubscribe(subscriptionEntry);\n }\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"multichainMethodCallValidatorMiddleware.cjs","sourceRoot":"","sources":["../../src/middlewares/multichainMethodCallValidatorMiddleware.ts"],"names":[],"mappings":"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","sourcesContent":["import { MultiChainOpenRPCDocument } from '@metamask/api-specs';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { isObject } from '@metamask/utils';\nimport type { JsonRpcError, JsonRpcParams } from '@metamask/utils';\nimport type {\n ContentDescriptorObject,\n MethodObject,\n OpenrpcDocument,\n ReferenceObject,\n} from '@open-rpc/meta-schema';\nimport dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document';\nimport { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document';\nimport type { Schema, ValidationError } from 'jsonschema';\nimport { Validator } from 'jsonschema';\n\nconst transformError = (\n error: ValidationError,\n param: ContentDescriptorObject,\n got: unknown,\n) => {\n // if there is a path, add it to the message\n const message = `${param.name}${\n error.path.length > 0 ? `.${error.path.join('.')}` : ''\n } ${error.message}`;\n\n return rpcErrors.invalidParams({\n message,\n data: {\n param: param.name,\n path: error.path,\n schema: error.schema,\n got,\n },\n });\n};\n\nconst v = new Validator();\n\nconst dereffedPromise = dereferenceDocument(\n MultiChainOpenRPCDocument as unknown as OpenrpcDocument,\n makeCustomResolver({}),\n);\n\n/**\n * Helper that utilizes the Multichain method specifications from `@metamask/api-specs`\n * to validate the params of a Multichain request.\n *\n * @param method - The request's method.\n * @param params - The request's optional JsonRpcParams object.\n * @returns an array of error objects for each validation error or an empty array if no errors.\n */\nconst multichainMethodCallValidator = async (\n method: string,\n params: JsonRpcParams | undefined,\n) => {\n const dereffed = await dereffedPromise;\n\n const methodToCheck = dereffed.methods.find(\n (m: MethodObject | ReferenceObject) => (m as MethodObject).name === method,\n ) as MethodObject | undefined;\n\n if (\n !methodToCheck ||\n !isObject(methodToCheck) ||\n !('params' in methodToCheck)\n ) {\n return [rpcErrors.methodNotFound({ data: { method } })] as JsonRpcError[];\n }\n\n const errors: JsonRpcError[] = [];\n for (const param of methodToCheck.params) {\n if (!isObject(params)) {\n return [rpcErrors.invalidParams()] as JsonRpcError[];\n }\n const p = param as ContentDescriptorObject;\n const paramToCheck = params[p.name];\n\n const result = v.validate(paramToCheck, p.schema as unknown as Schema, {\n required: p.required,\n });\n if (result.errors) {\n errors.push(\n ...result.errors.map((e) => {\n return transformError(e, p, paramToCheck) as JsonRpcError;\n }),\n );\n }\n }\n return errors;\n};\n\n/**\n * Middleware that validates the params of a Multichain method request\n * using the specifications from `@metamask/api-specs`.\n */\nexport const multichainMethodCallValidatorMiddleware = createAsyncMiddleware(\n async (request, _response, next) => {\n const errors = await multichainMethodCallValidator(\n request.method,\n request.params,\n );\n if (errors.length > 0) {\n throw rpcErrors.invalidParams<JsonRpcError[]>({ data: errors });\n }\n return await next();\n },\n);\n"]}
1
+ {"version":3,"file":"multichainMethodCallValidatorMiddleware.cjs","sourceRoot":"","sources":["../../src/middlewares/multichainMethodCallValidatorMiddleware.ts"],"names":[],"mappings":"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","sourcesContent":["import { MultiChainOpenRPCDocument } from '@metamask/api-specs';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { isObject } from '@metamask/utils';\nimport type { JsonRpcError, JsonRpcParams } from '@metamask/utils';\nimport type {\n ContentDescriptorObject,\n MethodObject,\n OpenrpcDocument,\n ReferenceObject,\n} from '@open-rpc/meta-schema';\nimport dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document';\nimport { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document';\nimport type { Schema, ValidationError } from 'jsonschema';\nimport { Validator } from 'jsonschema';\n\nconst transformError = (\n error: ValidationError,\n param: ContentDescriptorObject,\n got: unknown,\n) => {\n // if there is a path, add it to the message\n const message = `${param.name}${\n error.path.length > 0 ? `.${error.path.join('.')}` : ''\n } ${error.message}`;\n\n return rpcErrors.invalidParams({\n message,\n data: {\n param: param.name,\n path: error.path,\n schema: error.schema,\n got,\n },\n });\n};\n\nconst v = new Validator();\n\nconst dereffedPromise = dereferenceDocument(\n MultiChainOpenRPCDocument as unknown as OpenrpcDocument,\n makeCustomResolver({}),\n);\n\n/**\n * Helper that utilizes the Multichain method specifications from `@metamask/api-specs`\n * to validate the params of a Multichain request.\n *\n * @param method - The request's method.\n * @param params - The request's optional JsonRpcParams object.\n * @returns an array of error objects for each validation error or an empty array if no errors.\n */\nconst multichainMethodCallValidator = async (\n method: string,\n params: JsonRpcParams | undefined,\n) => {\n const dereffed = await dereffedPromise;\n\n const methodToCheck = dereffed.methods.find(\n (m: MethodObject | ReferenceObject) => (m as MethodObject).name === method,\n ) as MethodObject | undefined;\n\n if (\n !methodToCheck ||\n !isObject(methodToCheck) ||\n !('params' in methodToCheck)\n ) {\n return [rpcErrors.methodNotFound({ data: { method } })] as JsonRpcError[];\n }\n\n const errors: JsonRpcError[] = [];\n for (const param of methodToCheck.params) {\n if (!isObject(params)) {\n return [rpcErrors.invalidParams()] as JsonRpcError[];\n }\n const p = param as ContentDescriptorObject;\n const paramToCheck = params[p.name];\n\n const result = v.validate(paramToCheck, p.schema as unknown as Schema, {\n required: p.required,\n });\n if (result.errors) {\n errors.push(\n ...result.errors.map((e) => {\n return transformError(e, p, paramToCheck) as JsonRpcError;\n }),\n );\n }\n }\n return errors;\n};\n\n/**\n * Middleware that validates the params of a Multichain method request\n * using the specifications from `@metamask/api-specs`.\n */\nexport const multichainMethodCallValidatorMiddleware = createAsyncMiddleware(\n async (request, _response, next) => {\n const errors = await multichainMethodCallValidator(\n request.method,\n request.params,\n );\n if (errors.length > 0) {\n throw rpcErrors.invalidParams<JsonRpcError[]>({ data: errors });\n }\n return await next();\n },\n);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"multichainMethodCallValidatorMiddleware.mjs","sourceRoot":"","sources":["../../src/middlewares/multichainMethodCallValidatorMiddleware.ts"],"names":[],"mappings":"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","sourcesContent":["import { MultiChainOpenRPCDocument } from '@metamask/api-specs';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { isObject } from '@metamask/utils';\nimport type { JsonRpcError, JsonRpcParams } from '@metamask/utils';\nimport type {\n ContentDescriptorObject,\n MethodObject,\n OpenrpcDocument,\n ReferenceObject,\n} from '@open-rpc/meta-schema';\nimport dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document';\nimport { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document';\nimport type { Schema, ValidationError } from 'jsonschema';\nimport { Validator } from 'jsonschema';\n\nconst transformError = (\n error: ValidationError,\n param: ContentDescriptorObject,\n got: unknown,\n) => {\n // if there is a path, add it to the message\n const message = `${param.name}${\n error.path.length > 0 ? `.${error.path.join('.')}` : ''\n } ${error.message}`;\n\n return rpcErrors.invalidParams({\n message,\n data: {\n param: param.name,\n path: error.path,\n schema: error.schema,\n got,\n },\n });\n};\n\nconst v = new Validator();\n\nconst dereffedPromise = dereferenceDocument(\n MultiChainOpenRPCDocument as unknown as OpenrpcDocument,\n makeCustomResolver({}),\n);\n\n/**\n * Helper that utilizes the Multichain method specifications from `@metamask/api-specs`\n * to validate the params of a Multichain request.\n *\n * @param method - The request's method.\n * @param params - The request's optional JsonRpcParams object.\n * @returns an array of error objects for each validation error or an empty array if no errors.\n */\nconst multichainMethodCallValidator = async (\n method: string,\n params: JsonRpcParams | undefined,\n) => {\n const dereffed = await dereffedPromise;\n\n const methodToCheck = dereffed.methods.find(\n (m: MethodObject | ReferenceObject) => (m as MethodObject).name === method,\n ) as MethodObject | undefined;\n\n if (\n !methodToCheck ||\n !isObject(methodToCheck) ||\n !('params' in methodToCheck)\n ) {\n return [rpcErrors.methodNotFound({ data: { method } })] as JsonRpcError[];\n }\n\n const errors: JsonRpcError[] = [];\n for (const param of methodToCheck.params) {\n if (!isObject(params)) {\n return [rpcErrors.invalidParams()] as JsonRpcError[];\n }\n const p = param as ContentDescriptorObject;\n const paramToCheck = params[p.name];\n\n const result = v.validate(paramToCheck, p.schema as unknown as Schema, {\n required: p.required,\n });\n if (result.errors) {\n errors.push(\n ...result.errors.map((e) => {\n return transformError(e, p, paramToCheck) as JsonRpcError;\n }),\n );\n }\n }\n return errors;\n};\n\n/**\n * Middleware that validates the params of a Multichain method request\n * using the specifications from `@metamask/api-specs`.\n */\nexport const multichainMethodCallValidatorMiddleware = createAsyncMiddleware(\n async (request, _response, next) => {\n const errors = await multichainMethodCallValidator(\n request.method,\n request.params,\n );\n if (errors.length > 0) {\n throw rpcErrors.invalidParams<JsonRpcError[]>({ data: errors });\n }\n return await next();\n },\n);\n"]}
1
+ {"version":3,"file":"multichainMethodCallValidatorMiddleware.mjs","sourceRoot":"","sources":["../../src/middlewares/multichainMethodCallValidatorMiddleware.ts"],"names":[],"mappings":"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","sourcesContent":["import { MultiChainOpenRPCDocument } from '@metamask/api-specs';\nimport { createAsyncMiddleware } from '@metamask/json-rpc-engine';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { isObject } from '@metamask/utils';\nimport type { JsonRpcError, JsonRpcParams } from '@metamask/utils';\nimport type {\n ContentDescriptorObject,\n MethodObject,\n OpenrpcDocument,\n ReferenceObject,\n} from '@open-rpc/meta-schema';\nimport dereferenceDocument from '@open-rpc/schema-utils-js/build/dereference-document';\nimport { makeCustomResolver } from '@open-rpc/schema-utils-js/build/parse-open-rpc-document';\nimport type { Schema, ValidationError } from 'jsonschema';\nimport { Validator } from 'jsonschema';\n\nconst transformError = (\n error: ValidationError,\n param: ContentDescriptorObject,\n got: unknown,\n) => {\n // if there is a path, add it to the message\n const message = `${param.name}${\n error.path.length > 0 ? `.${error.path.join('.')}` : ''\n } ${error.message}`;\n\n return rpcErrors.invalidParams({\n message,\n data: {\n param: param.name,\n path: error.path,\n schema: error.schema,\n got,\n },\n });\n};\n\nconst v = new Validator();\n\nconst dereffedPromise = dereferenceDocument(\n MultiChainOpenRPCDocument as unknown as OpenrpcDocument,\n makeCustomResolver({}),\n);\n\n/**\n * Helper that utilizes the Multichain method specifications from `@metamask/api-specs`\n * to validate the params of a Multichain request.\n *\n * @param method - The request's method.\n * @param params - The request's optional JsonRpcParams object.\n * @returns an array of error objects for each validation error or an empty array if no errors.\n */\nconst multichainMethodCallValidator = async (\n method: string,\n params: JsonRpcParams | undefined,\n) => {\n const dereffed = await dereffedPromise;\n\n const methodToCheck = dereffed.methods.find(\n (m: MethodObject | ReferenceObject) => (m as MethodObject).name === method,\n ) as MethodObject | undefined;\n\n if (\n !methodToCheck ||\n !isObject(methodToCheck) ||\n !('params' in methodToCheck)\n ) {\n return [rpcErrors.methodNotFound({ data: { method } })] as JsonRpcError[];\n }\n\n const errors: JsonRpcError[] = [];\n for (const param of methodToCheck.params) {\n if (!isObject(params)) {\n return [rpcErrors.invalidParams()] as JsonRpcError[];\n }\n const p = param as ContentDescriptorObject;\n const paramToCheck = params[p.name];\n\n const result = v.validate(paramToCheck, p.schema as unknown as Schema, {\n required: p.required,\n });\n if (result.errors) {\n errors.push(\n ...result.errors.map((e) => {\n return transformError(e, p, paramToCheck) as JsonRpcError;\n }),\n );\n }\n }\n return errors;\n};\n\n/**\n * Middleware that validates the params of a Multichain method request\n * using the specifications from `@metamask/api-specs`.\n */\nexport const multichainMethodCallValidatorMiddleware = createAsyncMiddleware(\n async (request, _response, next) => {\n const errors = await multichainMethodCallValidator(\n request.method,\n request.params,\n );\n if (errors.length > 0) {\n throw rpcErrors.invalidParams<JsonRpcError[]>({ data: errors });\n }\n return await next();\n },\n);\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/multichain-api-middleware",
3
- "version": "1.2.4-preview-ee982ebe",
3
+ "version": "1.2.4-preview-91b0ac79",
4
4
  "description": "JSON-RPC methods and middleware to support the MetaMask Multichain API",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -72,7 +72,7 @@
72
72
  "ts-jest": "^27.1.4",
73
73
  "typedoc": "^0.24.8",
74
74
  "typedoc-plugin-missing-exports": "^2.0.0",
75
- "typescript": "~5.2.2"
75
+ "typescript": "~5.3.3"
76
76
  },
77
77
  "engines": {
78
78
  "node": "^18.18 || >=20"