diff --git a/docs/CAIPS/caip-25_wallet_createSession.md b/docs/CAIPS/caip-25_wallet_createSession.md new file mode 100644 index 000000000..a593dcaae --- /dev/null +++ b/docs/CAIPS/caip-25_wallet_createSession.md @@ -0,0 +1,405 @@ +--- +caip: 25 +title: Wallet Create Session JSON-RPC Method +author: Pedro Gomes (@pedrouid), Hassan Malik (@hmalik88) +discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/25 +status: Review +type: Standard +created: 2020-10-14 +updated: 2024-07-02 +requires: 2, 10, 171, 217, 285, 311, 312 +--- + +## Simple Summary + +CAIP-25 defines an authorization procedure for a chain agnostic provider to interface with a wallet as part of their initialization and/or "handshake" protocol. + +## Abstract + +This proposal has the goal to define a standard procedure for decentralized applications to interface with chain agnostic cryptocurrency wallets and other user agents which govern identities (including accounts) in multiple cryptographic systems. +It defines a lightweight protocol for negotiating and persisting authorizations during a session managed by a provider construct. + +## Motivation + +The motivation comes from the lack of standardization across blockchains to expose accounts and define the expected JSON-RPC methods to be used by an application through a provider connecting to a signer or other user agent. + +## Specification + +### Language + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" written in +uppercase in this document are to be interpreted as described in [RFC +2119][] + +### Definition + +#### Session Lifecycle + +The session is proposed by a caller and the response by the respondent is used as the baseline for an ongoing session between the two parties. +- When a wallet responds with a success response containing a `sessionId` (an entropic [identifier][CAIP-171]), the properties and authorization scopes that make up the session should be persisted and tracked over the life of the session by both parties in a discrete data store. +- When the wallet does not provide a `sessionId` in its initial response, the wallet MUST persist and track the properties and authorization scopes that make up the session. +The caller is not expected to persist session data or even a `sessionId`. +Note that wallets NOT returning `sessionId`s MUST implement additional methods and notifications to handle the full lifecycle of the session: + * [`wallet_getSession`][CAIP-312] to enable the caller to query for the current status of the session at any time. + * [`wallet_revokeSession`][CAIP-285] to explicitly end the session + * [`wallet_sessionChanged`][CAIP-311] to notify caller of updated session authorizations. + +After a session is established between wallet and caller, subsequent `wallet_createSession` calls can be used to update the properties and authorization scopes of the session. +- When a `sessionId` is returned in the initial `wallet_createSession` response, subsequent `wallet_createSession` calls either: + - include a previously used `sessionId` on the root of the request meaning this request is intended to modify that session, or + - do not include a `sessionId`, in which case a new session is created - the respondent generates a new `sessionId` and sends it with the success response - and the previous session dangles in parallel (until its expiration, if applicable), though maintaining concurrent sessions is discouraged (see Security Considerations). +- When the wallet does not provide a `sessionId` in its initial response, subsequent `wallet_createSession` calls overwrite the previous singular session between caller and wallet. + +When a user wishes to update the authorizations of an active session from within the wallet, the wallet should notify the caller of the changes with a [`wallet_sessionChanged`][CAIP-311] notification. + +If a connection is initially established without a `sessionId` and the wallet later implements `sessionId` support, the wallet can revoke the single session and notify the caller via `wallet_sessionChanged`. When the caller seeks to re-establish the session via `wallet_createSession`, the wallet should return a `sessionId` in the response. + +When a caller wishes revoke an active session, it can do so by calling [`wallet_revokeSession`][CAIP-285]. +- When a `sessionId` is returned in the initial `wallet_createSession` response, the caller MUST call `wallet_revokeSession` with the supplied `sessionId` to revoke that session. +- When the wallet does not provide a `sessionId` in its initial response, a call to `wallet_revokeSession` revokes the single active session between caller and wallet. + +For more detail on the lifecycle and management of sessions with and without `sessionId`s, see the informational [CAIP-316][]. + +#### Session Data and Metadata + +Initial and ongoing authorization requests are grouped into two top-level objects containing keyed [scopeObjects][CAIP-217], named `requiredScopes` and `optionalScopes` +respectively. +Each `scopeObject` in either parent object MUST be keyed uniquely within its parent, but these keys CAN appear in both +(i.e., additional properties of an authorization target in `requiredScopes` may be requested in a separate `scopeObject` with the same key in the `optionalScopes` array). + +Each `scopeObject` in these parent `...Scopes` objects can be keyed to a specific [CAIP-2][] network identifier, or to an entire [CAIP-104][] namespace. +`scopeObjects` keyed to an entire [CAIP-104][] namespace SHOULD contain a non-empty `references` array to be actionable, making them functionally equivalent to a series of identical `scopeObjects`, each keyed to one of the members of `references` expressed as a [CAIP-2][] scope. +An empty or absent `references` array SHOULD NOT be interpreted as a namespace-wide authorization (i.e. authorization for ANY network therein), but rather as a null authorization of 0 specified `references`s within that namespace. +(See [CAIP-217][] for more details on the structure of the typed objects included in these `...Scopes` objects.) + +The distinction between `requiredScopes` and `optionalScopes` is ultimately semantic, since a wallet may still choose to establish a connection authorizing a subset of requested networks or requested capabilities from each; the primary function of the distinction is to offer callers a mechanism for signaling which scopes they consider primary and which they consider secondary to their request, in order to better inform the authorization logic of the respondent. + +If a connection is being rejected, whether on the basis of end-user input or on the basis of evaluating `requiredScopes` against available capabilities, the respondent SHOULD choose its response based on trust: +e.g., one or more specific failure states MAY be sent (see [#### failure states](#failure-states) below) for trusted counterparties, but an `undefined` response (or no response, depending on implementation) MAY also be sent to prevent incentivizing unwanted requests and to minimize the surface for fingerprinting of public web traffic (See Privacy Considerations below). + +After parsing and authorizing separately all the networks and capabilities within each, a respondent establishes a connection by returning a success response that organizes all authorized features of each authorized scope in a single unified object of `scopeObject`s called `sessionScopes`. +In the case of identically-keyed `scopeObject`s appearing in both top-level objects in the request (`requestedScopes` and `optionalScopes`), the identically-scoped objects MUST be merged in the response, since `sessionScopes` MUST NOT contain redundant keys (see examples below). +However, respondents MUST NOT restructure scopes (e.g., by folding properties from a [CAIP-2][]-keyed, chain-specific scope object into a [CAIP-104][]-keyed, namespace-wide scope object) as this may introduce ambiguities (See Security Considerations below). + +### Request + +The application would interface with a provider to authorize that provider with a given set of parameters by calling the following JSON-RPC request + +Example: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_createSession", + "params": { + "requiredScopes": { + "eip155": { + "references": ["1", "137"], + "methods": ["eth_sendTransaction", "eth_signTransaction", "eth_sign", "get_balance", "personal_sign"], + "notifications": ["accountsChanged", "chainChanged"] + }, + "eip155:10": { + "methods": ["get_balance"], + "notifications": ["accountsChanged", "chainChanged"] + }, + "eip155:0": { + "methods": ["wallet_getPermissions", "wallet_creds_store", "wallet_creds_verify", "wallet_creds_issue", "wallet_creds_present"], + "notifications": [] + }, + "cosmos": { + ... + } + }, + "optionalScopes":{ + "eip155:42161": { + "methods": ["eth_sendTransaction", "eth_signTransaction", "get_balance", "personal_sign"], + "notifications": ["accountsChanged", "chainChanged"] + }, + "scopedProperties": { + "eip155:42161": { + "extension_foo": "bar" + } + }, + "sessionProperties": { + "expiry": "2022-12-24T17:07:31+00:00", + "caip154-mandatory": "true" + } + } +} +``` + +The JSON-RPC method is labeled as `wallet_createSession` and its `params` object contains "requiredScopes" and/or "optionalScopes" objects populated with [CAIP-217][] "scope objects" keyed to [CAIP-217][] scope strings. + +- The `requiredScopes` object MUST contain 1 or more `scopeObjects`, if present. +- The `optionalScopes` object MUST contain 1 or more `scopeObjects`, if present. + +A third object is the `scopedProperties` object, which also MUST contain 1 or more objects if present. +Each object should be keyed to the scope of a `sessionScopes` member to which it corresponds. +All properties of each object in `scopedProperties` MUST be interpreted by the respondent as proposals or declarations rather than as requirements. +In addition to making additional properties of or metadata about the corresponding `sessionScopes` member explicit, they can also annotate, support, or extend the negotiation of scope proposals (e.g., providing connection information about unfamiliar scopes, or which accounts to expose to each). + +A fourth object, `sessionProperties`, is optional and its shape undefined. +It is intended for metadata or additional information not bound to any specific authorization scope, but made "global" to the connection. + +The respondent SHOULD ignore and drop from its response any properties not defined in this document or in another CAIP document extending this protocol which the respondent has implemented in its entirety; +similarly, the `requiredScopes`, `optionalScopes`, and `sessionScopes` objects returned by the respondent SHOULD contain only valid [CAIP-217][] objects, and properties not defined in [CAIP-217][] SHOULD also be dropped from each of those objects. +The same absolute security posture is not expected for the metadata objects `scopedProperties` and `sessionProperties`, but caution is still recommended for such extensions: +callers and respondents alike SHOULD allow for their counterparties dropping or ignoring unfamiliar members from either. + +When a `sessionId` is returned with the initial success response, requesting applications and respondents alike are expected to manage state for the connection, including `scopedProperties` and `sessionProperties`, and that same `sessionId` should be added to the `wallet_createSession` request to update the associated session. +When no `sessionId` is included in an initial success response, a caller does not need to maintain `sessionId` state and can assume the extension methods defined in [CAIP-311][] and [CAIP-312][] are available for refreshing and updating the session directly. +See [CAIP-316][] for more on lifecycle management. +if multiple concurrent connections are allowed, callers are expected to track, persist and identify them separately by the unique `sessionId` returned initially. + +### Response + +The wallet can respond to this method with either a success result or an error message. + +#### Success + +The successful result MAY contain a string (keyed as `sessionId` with a value conformant to [CAIP-171][]). As described above, if a `sessionId` is returned in the response, the caller should persist and track the properties and authorization scopes associated with this `sessionid`. If the wallet does not return a `sessionId` in the response, the connection will only consist of one session at a time, the contents of which are always retrievable for the caller via [`wallet_getSession`][CAIP-312]. + +The successful result MUST contain an object called `sessionScopes` which contains 1 or more `scopeObjects`. +- All required `scopeObjects` and all, none, or some of the optional `scopeObject`s (at the discretion of the provider) MUST be included if successful. +- Unlike the request, each scope object MUST also contain an `accounts` array, +containing 0 or more [CAIP-10][]-conformant accounts authorized for the session +and valid in that scope. Additional constraints on the accounts authorized for a given session MUST be applied conformant to the namespace's [CAIP-10][] profile, if one has been specified. + +A `scopedProperties` object MAY also be present, each member of which corresponds to exactly 1 `sessionScope`. +This is intended for expressing connection-specific or non-standardized extensions to `sessionScope`. +Each object in `scopedProperties` MUST be keyed to a `scopeString`, and SHOULD correspond to a `sessionScopes` entry with the same key. +There are no type, depth, or shape constraints on the contents of each property in `scopedProperties`. +If an object in `scopedProperties` is keyed to a `scopeString` not currently authorized for the session, it SHOULD be ignored. + +A `sessionProperties` object MAY also be present, with no protocol-wide shape constraints or semantics assumed. +This is intended for expressing metadata about the CAIP-25 connection and accessible to ALL `sessionScopes` equally. +There are no type, depth, or shape constraints on the contents of `sessionProperties`. + +An example of a successful response follows: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "sessionId": "0xdeadbeef", + "sessionScopes": { + "eip155": { + "references": ["1", "137"], + "methods": ["eth_sendTransaction", "eth_signTransaction", "get_balance", "eth_sign", "personal_sign"] + "notifications": ["accountsChanged", "chainChanged"], + "accounts": ["eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", "eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb"] + }, + "eip155:10": { + "methods": ["get_balance"], + "notifications": ["accountsChanged", "chainChanged"], + "accounts": [] + }, + "eip155:42161": { + "methods": ["personal_sign"], + "notifications": ["accountsChanged", "chainChanged"], + "accounts":["eip155:42161:0x0910e12C68d02B561a34569E1367c9AAb42bd810"], + "rpcDocuments": "https://example.com/wallet_extension.json" + }, + "eip155:0": { + "methods": ["wallet_getPermissions", "wallet_creds_store", "wallet_creds_verify", "wallet_creds_issue", "wallet_creds_present"], + "notifications": [] + }, + "cosmos": { + ... + } + }, + "scopedProperties": { + "eip155:42161": { + "walletExtensionConfig": { + "foo": "bar" + } + } + }, + "sessionProperties": { + "expiry": "2022-11-31T17:07:31+00:00", + "globalConfig": { + "foo": "bar" + } + } + } +} +``` + +#### Failure States + +The response MUST NOT be a JSON-RPC success result in any of the following failure states. + +##### Generic Failure Code + +Unless the dapp is known to the wallet and trusted, the generic/undefined error response, + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "error": { + "code": 0, + "message": "Unknown error" + } +} +``` + +is RECOMMENDED for any of the following cases: + +- the user denies consent for exposing accounts that match the requested and + approved networks/"chains", +- the user denies consent for requested methods, +- the user denies all requested or any required scope objects, +- the wallet cannot support all requested or any required scope objects, +- the requested networks/"chains" are not supported by the wallet, or +- the requested methods are not supported by the wallet + +##### Trusted Failure Codes + +More informative error messages MAY be sent in trusted-counterparty circumstances, although extending this trust too widely may contribute to widespread fingerprinting and analytics which corrode herd privacy (see [Privacy Considerations](#privacy-considerations) below). +The core error messages over trusted connections are as follows: + +The valid error messages codes are the following: + +- Unknown error OR no scopes were authorized + - code = 5000 + - message = "Unknown error with request" +- When user disapproves accepting calls with the request methods + - code = 5001 + - message = "User disapproved requested methods" +- When user disapproves accepting calls with the request notifications + - code = 5002 + - message = "User disapproved requested notifications" +- When provider evaluates networks requested by chainId as not supported + - code = 5100 + - message = "Requested networks are not supported" +- When provider evaluates requested methods to not be supported + - code = 5101 + - message = "Requested methods are not supported" +- When provider evaluates requested notifications to not be supported + - code = 5102 + - message = "Requested notifications are not supported" + + +##### Trust-Agnostic Malformed Request Failure Codes + +Regardless of caller trust level, the following error responses can reduce friction and user experience problems in the case of malformed requests. + +- When provider does not recognize one or more requested method(s) + - code = 5201 + - message = "Unknown method(s) requested" +- When provider does not recognize one or more requested notification(s) + - code = 5202 + - message = "Unknown notification(s) requested" +- When a badly-formed request defines one `chainId` two ways + - code = 5204 + - message = "ChainId defined in two different scopes" +- Invalid scopedProperties Object + - code = 5300 + - message = "Invalid scopedProperties requested" +- scopedProperties requested outside of scopedProperties Object + - code = 5301 + - message = "scopedProperties can only be outside of sessionScopes" +- Invalid sessionProperties Object + - code = 5302 + - message = "Invalid sessionProperties requested" + +Note: respondents SHOULD to implement support for core RPC Documents per each +supported namespace to avoid sending error messages 5201 and 5202 in cases where +0, 5101 or 5102 would be more appropriate. Failure to do so may leak versioning +or feature-completeness information to a malicious or fingerprinting caller. + +## Security Considerations + +The crucial security function of a shared session negotiated and maintained by a +series of CAIP-25 calls is to reduce ambiguity in authorization. This requires +a potentially counterintuitive structuring of the building-blocks of a +Chain-Agnostic session into scopes at the "namespace-wide" ([CAIP-104][]) or at +the "chain-specific" ([CAIP-2][]) level; for this reason, requests and responses +are structures as objects full of objects keyed to these scopes, formatted either as a +[CAIP-104][] scheme OR as a full [CAIP-2][]. While internal systems are free to +translate this object into other structures, preserving it in the CAIP-25 +interface is crucial to the unambiguous communication between caller and +respondent about what exact authorization is granted. + +## Privacy Considerations + +One major risk in browser-based or HTTP-based communications is "fingerprinting +risk", i.e. the risk that public or intercepted traffic can be used to +deanonymize browsers and/or wallets deductively based on response times, error +codes, etc. To minimize this risk, and to minimize the data (including +behavioral data) leaked by responses to potentially malicious CAIP-25 calls, +respondents are recommended to ignore calls + +1. which the respondent explicitly does not authorize, +2. which are rejected automatically or by policy, or +3. which are rejected for unknown reasons. + +"Ignoring" these calls means responding to all three in a way that is +*indistinguishable* to a malicious caller or observer which might deduce +information from differences in those responses (including the time taken to +provide them). Effectively, this means allowing requests in all three cases to +time out even if the end-user experience might be better served by +differentiating them, particularly in complex multi-party architectures where +parties on one side of this interface need to have a shared understanding of why +a request did not receive a response. At scale, however, better user experiences +in a single architecture or context can contribute to a systemic erosion of +anonymity. + +Given this "silent time out" behavior, the best strategy to ensure good user +experience is not to request too many properties in the initial establishment of +a session and to iteratively and incrementally expand session authorization over +time. This also contributes to a more consentful experience overall and +encourages progressive trust establishment across complex architectures with +many distinct actors and agents. + +Another design pattern that accomodates the "silent time out" behavior is minor +updates to the session. For example, a caller sending a request identical to a +previous request (or a previous response) except for a new session expiry +further in the future could expect one of exactly three responses: + +1. An identical response to the previous request (meaning the session extension was denied); +2. A response identical expect that it includes the new, extended session expiry; or, +3. A silent time out (meaning the calling behavior was malformed in ways the +respondent cannot understand, or the respondent choses not to make explicit how +the request was malformed, or the end-user rejected them, or the request itself +was in violation of policy). + +## Changelog + +-- 2024-07-29: added lifecycle management methods and notification for single session connections, see [CAIP-316][] for equivalence chart and diagrams +- 2024-07-16: redefined requiredScopes to be functionally equivalent to optionalScopes, but semantically different; previously, authorizing less than 100% of reqScopes required rejecting the connection +- 2023-03-29: refactored out scopeObject syntax as separate CAIP-217, simplified +- 2022-11-26: add mandatory indexing by session identifier (i.e. CAIP-171 requirement) +- 2022-10-26: Addressed Berlin Gathering semantics issues and params syntax; consolidated variants across issues and forks post-Amsterdam Gathering + +## Links + +- [CAIP-2][] - Chain ID Specification +- [CAIP-10][] - Account ID Specification +- [CAIP-104][] - Definition of Chain Agnostic Namespaces or CANs +- [CAIP-171][] - Session Identifier, i.e. syntax and usage of `sessionId`s +- [CAIP-217][] - Authorization Scopes, i.e. syntax for `scopeObject`s +- [CAIP-285][] - `wallet_revokeSession` Specification +- [CAIP-312][] - `wallet_getSession` Specification +- [CAIP-311][] - `wallet_sessionChanged` Specification +- [CAIP-316][] - Session Lifecycle Management equivalence chart and diagrams + +[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2 +[CAIP-10]: https://chainagnostic.org/CAIPs/caip-10 +[CAIP-104]: https://chainagnostic.org/CAIPs/caip-104 +[CAIP-171]: https://chainagnostic.org/CAIPs/caip-171 +[CAIP-217]: https://chainagnostic.org/CAIPs/caip-217 +[CAIP-285]: https://chainagnostic.org/CAIPs/caip-285 +[CAIP-312]: https://chainagnostic.org/CAIPs/CAIP-312 +[CAIP-311]: https://chainagnostic.org/CAIPs/CAIP-311 +[CAIP-316]: https://chainagnostic.org/CAIPs/caip-316 +[namespaces]: https://namespaces.chainagnostic.org +[RFC3339]: https://datatracker.ietf.org/doc/html/rfc3339#section-5.6 + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). diff --git a/docs/CAIPS/caip-27_wallet_invokeMethod.md b/docs/CAIPS/caip-27_wallet_invokeMethod.md new file mode 100644 index 000000000..f52107c47 --- /dev/null +++ b/docs/CAIPS/caip-27_wallet_invokeMethod.md @@ -0,0 +1,164 @@ +--- +caip: 27 +title: Wallet Invoke Method JSON-RPC Method +author: Pedro Gomes (@pedrouid), Hassan Malik (@hmalik88) +discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/27 +status: Draft +type: Standard +created: 2020-12-12 +updated: 2024-08-12 +requires: 2, 25, 171, 217, 316 +--- + +## Simple Summary + +CAIP-27 defines a JSON-RPC method for a decentralized application to invoke a targeted JSON-RPC method, marked for a specified target previously authorized by a valid [scopeObject][CAIP-217], and tagged with a [sessionId][CAIP-171] for maintaining session continuity if applicable. + +## Abstract + +This proposal has the goal of defining a standard method for decentralized applications to invoke JSON-RPC methods from decentralized applications directed to a given, previously-authorized target network. +These "target networks" can include nodes of a specific blockchain (accessed via the user agent), the consensus community within a cryptographic protocol, or a user agent's network-specific state. +The JSON-RPC method is nested inside a JSON-RPC "envelope", which takes as required argument a [CAIP-2] identifier designating the target network, with an optional second argument for the [sessionId][CAIP-171] of that session if applicable (see [CAIP-316]). +These two properties MAY be inherited from a persistent session created by [CAIP-25][], but could also be used as part of other session management mechanisms. + +## Motivation + +This routing envelope avoids ambiguity when applications interface with a multi-chain agent (e.g. a cryptocurrency wallets which supports the same method on multiple chains in a given RPC namespace, or supports methods with the same name on multiple [namespaces]). + +## Specification + +### Language + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" written in uppercase in this document are to be interpreted as described in [RFC 2119][] + +### Definition + +The JSON-RPC provider is able to invoke a single JSON-RPC request accompanied by a [CAIP-2][] compatible `chainId` authorized by a pre-existing session. +If that pre-existing session was initiated by a [CAIP-25] response containing a [sessionId][CAIP-171], this `sessionId` value should also be returned at the top level of the `wallet_invokeMethod` envelope (see [CAIP-316] for more context on managing sessions with and without `sessionId` keys). + +### Request + +The application would interface with an JSON-RPC provider to make request as follows: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_invokeMethod", + "params": { + "sessionId": "0xdeadbeef", + "scope": "eip155:1", + "request": { + "method": "eth_sendTransaction", + "params": [ + { + "to": "0x4B0897b0513FdBeEc7C469D9aF4fA6C0752aBea7", + "from": "0xDeaDbeefdEAdbeefdEadbEEFdeadbeefDEADbEEF", + "gas": "0x76c0", + "value": "0x8ac7230489e80000", + "data": "0x", + "gasPrice": "0x4a817c800" + } + ] + } + } +} +``` + +The JSON-RPC method is labeled as `wallet_invokeMethod` and expects three parameters, **two of them required**: + +- **sessionId** (conditional) - [CAIP-171][] `SessionId` disambiguates an open session in a multi-session actor; it is required in some sessions, such as [CAIP-25][] sessions created by a response containing one, and SHOULD be omitted in other sessions, such as [CAIP-25] sessions created by a response not containing one (see [CAIP-316]). +- **scope** (required) - a valid [CAIP-2][] network identifier, previously authorized by or within a `scopeObject` in the active session +- **request** (required) - an object containing the fields: + - **method** (required) - the JSON-RPC method to invoke (previously authorized for the targeted network) + - **params** (required) - JSON-RPC parameters to invoke (may be empty but must be set) + +### Validation + +1. A respondent SHOULD check the `scope` against active session's `scopeObject`s before executing or responding to such a request, and SHOULD invalidate a request for a scope not previously authorized. +2. The respondent SHOULD check that `request.method` is authorized for the specified scope, and SHOULD invalidate a request for a scope not previously authorized. +3. The respondent MAY check that the `request.params` are valid for `request.method`, if its syntax is known to it. +4. The respondent MAY apply other logic or validation. +5. The respondent MAY chose to drop invalid requests or return an error message, but it MUST NOT route or submit them. + +### Response + +Upon successful validation, the respondent will submit or route the request to the targeted network. +If the targeted network returns a response to the respondent, the respondent MAY forward this response to the caller. + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "sessionId": "0xdeadbeef", + "scope": "eip155:1", + "result": { + "method": "eth_sendTransaction", + "result": "0x4e306b5a5a37532e1734503f7d2427a86f2c992fbe471f5be403b9f734e667c8" + } + } +} +``` + +Constraints on, metadata about, or envelopes for response-forwarding MAY be set by [namespace][namespaces] profiles of this CAIP. + +#### Error Handling + +Note that errors pertaining to the connection or session should replace the top-level `"result"` object, but cannot be matched to requests sent without a unique `id`: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "error": { + "code": -32700, + "message": "Parse Error" + } +} +``` + +Conversely, errors specific to the method passed or its RPC namespace should be expressed INSIDE the result of a response envelope, with targeting information preserved: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "sessionId": "0xdeadbeef", + "scope": "eip155:1", + "error": { + "code": 4100, + "message": "The requested account and/or method has not been authorized by the user." + } + } +} +``` + +The latter category of error depend on the design of the passed method defined within the given RPC namespace, and MAY be defined by a [namespace][namespaces] profile of this CAIP if not in the underlying documentation for that RPC community. + +## Backwards Compatibility + +Early drafts of this specification did not constrain `scope` to [CAIP-2] identifiers, but rather to any [valid scopeStrings][CAIP-217] previously-authorized, including namespace-wide ones. +No known implementations in production took advantage of this affordance, as to date no RPC [namespaces] have been defined that could receive such requests regardless of [CAIP-2] network identifiers. + +## Links + +- [CAIP-2]: Network identifiers +- [CAIP-25]: Authorized session definition +- [CAIP-171]: Session identifiers for Authorized Sessions +- [CAIP-217]: Scope Definitions for Authorized Sessions +- [CAIP-316]: Managing Authorized Sessions With and Without Identifiers +- [Namespaces]: CASA RPC Namespaces + +[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2 +[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25 +[CAIP-171]: https://chainagnostic.org/CAIPs/caip-171 +[CAIP-217]: https://chainagnostic.org/CAIPs/caip-217 +[CAIP-316]: https://chainagnostic.org/CAIPs/caip-316 +[namespaces]: https://namespaces.chainagnostic.org/ +[RFC 2119]: https://www.ietf.org/rfc/rfc2119.txt + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). diff --git a/docs/CAIPS/caip-311_sessionChanged.md b/docs/CAIPS/caip-311_sessionChanged.md new file mode 100644 index 000000000..73273591b --- /dev/null +++ b/docs/CAIPS/caip-311_sessionChanged.md @@ -0,0 +1,78 @@ +--- +caip: 311 +title: JSON-RPC Event for Session Authorization Updates +author: Alex Donesky (@adonesky1) +discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/285/files +status: Draft +type: Standard +created: 2024-07-12 +requires: 25, 217 +--- + +## Simple Summary + +CAIP-311 introduces the `wallet_sessionChanged` event for notifying callers party to an active [CAIP-25][] session of updates to session authorizations made by users directly in the wallet. + +## Abstract + +This proposal aims to extend the [CAIP-25][] standard by defining a new JSON-RPC event for notifying the caller of updates to session authorizations. This event allows wallets to dynamically inform callers of changes to authorizations made by users on the wallet side, without having to initiate a new session each time. + +## Motivation + +The motivation behind this proposal is to provide bidirectional management of [CAIP-25][] session authorizations. The proposed event provides an intuitive way to notify dapps of changes to authorizations within an active session, simplifying the management of session lifecycles. + +## Definition + +## Specification + +This event is published by the wallet to notify the callers of updates to a shared session's authorization scopes. The event payload contains the new `sessionScopes`. If a connection between the wallet and the caller is severed and the possibility of missed events arises, the caller should immediately call `wallet_getSession` to retrieve the current session scopes. + +**Notification Parameters:** + +- `sessionId` (string, optional): The session identifier. +- `sessionScopes` (object of `scopeObject` objects, required): An object containing the full updated session scopes, each formatted according to [CAIP-217][]. + +**Notification:** + +```jsonc +{ + "method": "wallet_sessionChanged", + "params": { + "sessionScopes": { + "eip155:1": { + "methods": ["eth_signTransaction", "eth_sendTransaction"], + "notifications": ["accountsChanged"], + "accounts": ["eip155:1:0xabc123"] + }, + "eip155:137": { + "methods": ["eth_sendTransaction"], + "notifications": [], + "accounts": ["eip155:137:0xdef456"] + } + } + } +} +``` + +## Security Considerations + +The introduction of this lifecycle method must ensure that only authorized parties can retrieve the authorizations of a session. Proper authentication and authorization mechanisms must be in place to prevent unauthorized access or modifications. + +To achieve this, it is recommended to establish a connection over domain-bound or other 1:1 transports. Where applicable, additional binding to a `sessionId` is recommended to ensure secure session management. This approach helps to create a secure communication channel that can effectively authenticate and authorize session-related requests, minimizing the risk of unauthorized access or session hijacking. + +## Links + +- [CAIP-25] - JSON-RPC Handshake Protocol Specification. i.e `wallet_createSession` +- [CAIP-217]- Authorization Scopes, i.e. syntax for `scopeObject`s + +[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25 +[CAIP-217]: https://chainagnostic.org/CAIPs/caip-217 +[CAIP-311]: https://chainagnostic.org/CAIPs/caip-311 +[CAIP-312]: https://chainagnostic.org/CAIPs/caip-312 +[CAIP-316]: https://chainagnostic.org/CAIPs/caip-316 + + +## Copyright + +Copyright and related rights waived via +[CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/docs/CAIPS/caip-312_wallet_getSession.md b/docs/CAIPS/caip-312_wallet_getSession.md new file mode 100644 index 000000000..4701c3e9c --- /dev/null +++ b/docs/CAIPS/caip-312_wallet_getSession.md @@ -0,0 +1,121 @@ +--- +caip: 312 +title: JSON-RPC Method for Retrieving Session Authorizations +author: Alex Donesky (@adonesky1) +discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/285/files +status: Draft +type: Standard +created: 2024-07-13 +requires: 25, 217 +--- + +## Simple Summary + +CAIP-312 introduces the `wallet_getSession` method for retrieving authorizations from an active [CAIP-25][] initiated session. + +## Abstract + +This proposal aims to extend the [CAIP-25][] standard by defining a new JSON-RPC method for retrieving authorizations within a session. This method allows callers to dynamically retrieve authorizations and properties. + +## Motivation + +The motivation behind this proposal is to enhance the flexibility of [CAIP-25][] by enabling the retrieval of session authorizations at any time. The proposed method provides an intuitive way to retrieve authorizations for an active session, allowing callers to access session data without having to persist and track it over the full life of the method. + +## Specification + +### Definition + +The `wallet_getSession` method returns an active session. +If a `sessionId` is provided, it returns the authorizations for that specific session; +If no `sessionId` parameter is provided - and there is a single active session with no `sessionId` assigned - it returns the session authorizations and properties for that session; +otherwise, an appropriate error message; + +**Parameters:** + +- `sessionId` (string, optional): The session identifier. + +### Request + +The caller would interface with a wallet via the same provider by which it called `wallet_createSession` to retrieve a session by calling the following JSON-RPC request: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "method": "wallet_getSession", + "params": {} +} +``` + +### Response + +An example of a successful response follows: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "result": { + "sessionScopes": { + "eip155:1": { + "methods": ["eth_signTransaction"], + "notifications": ["accountsChanged"], + "accounts": ["eip155:1:0xabc123"] + }, + "eip155:137": { + "methods": ["eth_sendTransaction"], + "notifications": ["chainChanged"], + "accounts": ["eip155:137:0xdef456"] + }, + "solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ": { + "methods": ["getBalance", "getAccountInfo", "sendTransaction", "getBlock"], + "notifications": [], + "accounts": ["solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ:4Nd1mS8AUwK3kU3gdiAM6QCvqhA7Do8rKtMXsGyqrJxy"] + } + } +} +``` + +### Failure States + +The response MUST NOT be a JSON-RPC success result in any of the following failure states. + +#### Generic Failure Code + +Unless the dapp is known to the wallet and trusted, the generic/undefined error response: + +```jsonc +{ + "id": 1, + "jsonrpc": "2.0", + "error": { + "code": 0, + "message": "Unknown error" + } +} +``` + +is RECOMMENDED for any of the following cases: + +- a `sessionId` is passed but not recognized, +- no `sessionId` is passed and only active session(s) have `sessionId`s, or +- there are no active sessions + +## Security Considerations + +The introduction of this lifecycle method must ensure that only authorized parties can retrieve the authorizations of a session. Proper authentication and authorization mechanisms must be in place to prevent unauthorized access or modifications. + +To achieve this, it is recommended to establish a connection over domain-bound or other 1:1 transports. Where applicable, additional binding to a `sessionId` is recommended to ensure secure session management. This approach helps to create a secure communication channel that can effectively authenticate and authorize session-related requests, minimizing the risk of unauthorized access or session hijacking. + +## Links + +- [CAIP-25] - JSON-RPC Handshake Protocol Specification. i.e `wallet_createSession` +- [CAIP-217]- Authorization Scopes, i.e. syntax for `scopeObject`s + +[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25 +[CAIP-217]: https://chainagnostic.org/CAIPs/caip-217 + +## Copyright + +Copyright and related rights waived via +[CC0](https://creativecommons.org/publicdomain/zero/1.0/). diff --git a/docs/CAIPS/caip-319_wallet_notify.md b/docs/CAIPS/caip-319_wallet_notify.md new file mode 100644 index 000000000..df838ff0e --- /dev/null +++ b/docs/CAIPS/caip-319_wallet_notify.md @@ -0,0 +1,111 @@ +--- +caip: 319 +title: Wallet Notification JSON-RPC Method +author: Alex Donesky (@adonesky1) +discussions-to: https://github.com/ChainAgnostic/CAIPs/pull/X +status: Draft +type: Standard +created: 2024-08-01 +requires: 2, 25, 171, 217 +--- + +## Simple Summary + +CAIP-319 defines a JSON-RPC method for a wallet to send notifications to a +caller in a context authorized by or in a valid [scopeObject][CAIP-217] and, +optionally, tagged with a [sessionId][CAIP-171] for maintaining session +continuity if applicable. + +## Abstract + +This proposal aims to define a standard method for wallets to send notifications +to callers regarding events or state changes related to a specific, +previously-authorized target network (such as nodes of a specific blockchain or +consensus community within a protocol). It requires a valid +[scopeObject][CAIP-217]. It MAY be tagged with a [sessionId][CAIP-171] if the +[CAIP-25][] session in which it is authorized is keyed by a sessionId (see +[CAIP-316][] for more details). These two properties MAY be inherited from a +persistent session created by [CAIP-25][], but could also be used as part of +other session management mechanisms. + +## Motivation + +The motivation for this proposal comes from the need for standardized, +chain-specific notifications from wallets to applications in a concurrent +multi-chain connection where methods and notifications with the same namespace may +exist across chains or namespaces. + +## Specification + +### Definition + +The wallet is able to send a single JSON-RPC notification accompanied by a +[CAIP-2][] compatible `chainId`, and optionally scoped by the +[sessionId][CAIP-171] of a pre-existing session if applicable. + +### Notification + +The wallet or user agent would send a notification to the application as +follows: + +```jsonc +{ + "jsonrpc": "2.0", + "method": "wallet_notify", + "params": { + "sessionId": "0xdeadbeef", + "scope": "eip155:1", + "notification": { + "method": "eth_subscription", + "params": { + "subscription": "0x12345678", + "result": { + "blockNumber": "0x1234", + "transactionHash": "0x5678", + "logIndex": "0x9abc" + } + } + } + } +} +``` + +The JSON-RPC method is labeled as `wallet_notify` and expects two required +parameters: + +- **scope** - a valid [CAIP-2][] chainId previously authorized to the caller within a [CAIP-25][] session +- **notification** - an object containing the fields: + - **method** - JSON-RPC notification method name previously authorized to the caller within a [CAIP-25][] session + - **params** - JSON-RPC notification parameters + +Additionally, it MAY include an **optional parameter**: + +- **sessionId** - [CAIP-171][] `sessionId` referencing a known, open session + +### Validation + +1. The application MUST check the scope against the identified session object + before processing the notification. +2. The application SHOULD verify that the notification.method is one it expects + to receive for that specific scope. +3. The application MAY apply other logic or validation to the notification data. +4. The application MAY choose to ignore notifications it doesn't recognize or + considers invalid. + +### Response +As this syntax simply provides a wrapper to a standard [JSON-RPC notification][] +and functions as one itself, no response is expected from the application. The +wallet or user agent SHOULD NOT wait for a response before continuing its +operations. + +## Links +[CAIP-2]: https://chainagnostic.org/CAIPs/caip-2 +[CAIP-25]: https://chainagnostic.org/CAIPs/caip-25 +[CAIP-171]: https://chainagnostic.org/CAIPs/caip-171 +[CAIP-217]: https://chainagnostic.org/CAIPs/caip-217 +[CAIP-316]: https://chainagnostic.org/CAIPs/caip-316 +[JSON-RPC notification]: https://www.jsonrpc.org/specification#notification + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE). diff --git a/package.json b/package.json index 2d2127f5e..6670ab37d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "packages/sdk-socket-server-next", "packages/sdk-install-modal-web", "packages/sdk-communication-layer", + "packages/sdk-multichain", "packages/sdk", "packages/sdk-react", "packages/sdk-react-native", @@ -34,7 +35,7 @@ "postinstall": "patch-package", "link-packages": "./scripts/link-packages.sh", "prepare": "husky install", - "dev:core": "turbo run dev --parallel --filter=@metamask/sdk-communication-layer --filter=@metamask/sdk --filter=@metamask/sdk-react", + "dev:core": "turbo run dev --parallel --filter=@metamask/sdk-communication-layer --filter=@metamask/sdk-multichain --filter=@metamask/sdk --filter=@metamask/sdk-react", "lint": "yarn workspaces foreach --no-private run lint", "lint:changelogs": "yarn workspaces foreach --no-private run lint:changelog", "lint:eslint": "yarn workspaces foreach --no-private run lint:eslint", diff --git a/packages/examples/nextjs-demo/next.config.js b/packages/examples/nextjs-demo/next.config.js index 767719fc4..9907b6d18 100644 --- a/packages/examples/nextjs-demo/next.config.js +++ b/packages/examples/nextjs-demo/next.config.js @@ -1,4 +1,12 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {} +const nextConfig = { + webpack: (config) => { + config.externals.push({ + 'bufferutil': 'bufferutil', + 'utf-8-validate': 'utf-8-validate', + }) + return config + }, +} -module.exports = nextConfig +module.exports = nextConfig \ No newline at end of file diff --git a/packages/examples/nextjs-demo/package.json b/packages/examples/nextjs-demo/package.json index 983502ce2..31a90b7ac 100644 --- a/packages/examples/nextjs-demo/package.json +++ b/packages/examples/nextjs-demo/package.json @@ -10,6 +10,7 @@ "allow-scripts": "echo 'n/a'" }, "dependencies": { + "@metamask/providers": "^18.3.1", "@metamask/sdk-react": "^0.30.0", "@types/node": "20.2.1", "@types/react": "18.2.6", @@ -20,5 +21,18 @@ "react": "18.2.0", "react-dom": "18.2.0", "typescript": "5.0.4" + }, + "devDependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-proposal-json-modules": "^7.25.9", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/preset-env": "^7.26.0", + "babel-loader": "^9.2.1", + "bufferutil": "^4.0.9", + "utf-8-validate": "^6.0.5" + }, + "resolutions": { + "@metamask/safe-event-emitter": "3.1.1" } } diff --git a/packages/examples/nextjs-demo/sdk-copy.sh b/packages/examples/nextjs-demo/sdk-copy.sh index 3bceb8beb..6a1aeac15 100755 --- a/packages/examples/nextjs-demo/sdk-copy.sh +++ b/packages/examples/nextjs-demo/sdk-copy.sh @@ -7,7 +7,7 @@ SDK_WORKSPACE_DIR="$( pwd; )"; COMM_LAYER_DIR="$SDK_WORKSPACE_DIR/packages/sdk-communication-layer" SDK_DIR="$SDK_WORKSPACE_DIR/packages/sdk" SDK_REACT_DIR="$SDK_WORKSPACE_DIR/packages/sdk-react" -SDK_REACT_UI_DIR="$SDK_WORKSPACE_DIR/packages/sdk-react-ui" +SDK_INSTALL_MODAL_WEB_DIR="$SDK_WORKSPACE_DIR/packages/sdk-install-modal-web" DAPP_DIR="$SDK_WORKSPACE_DIR/packages/examples/nextjs-demo" @@ -15,18 +15,27 @@ echo "SDK_DIR: $SDK_DIR" echo "COMM_LAYER_DIR: $COMM_LAYER_DIR" echo "DAPP_DIR: $DAPP_DIR" echo "SDK_REACT_DIR: $SDK_REACT_DIR" -echo "SDK_REACT_UI_DIR: $SDK_REACT_UI_DIR" +echo "SDK_INSTALL_MODAL_WEB_DIR: $SDK_INSTALL_MODAL_WEB_DIR" echo "########### START REPLACING SDK_COMMUNICATION_LAYER #########" cd $DAPP_DIR echo "Hack Metamask sdk && sdk-communication-layer packages..." ## hack to debug to latest unpublished version of the sdk -rm -rf node_modules/@metamask/sdk-communication-layer node_modules/@metamask/sdk node_modules/@metamask/sdk-react node_modules/@metamask/sdk-react-ui -cp -rf $COMM_LAYER_DIR node_modules/@metamask/ -cp -rf $SDK_DIR node_modules/@metamask/ -cp -rf $SDK_REACT_DIR node_modules/@metamask/ -cp -rf $SDK_REACT_UI_DIR node_modules/@metamask/ +rm -rf node_modules/@metamask/sdk-communication-layer/dist node_modules/@metamask/sdk/dist node_modules/@metamask/sdk-react/dist node_modules/@metamask/sdk-install-modal-web/dist +cp -rf $COMM_LAYER_DIR/dist node_modules/@metamask/sdk-communication-layer/dist +cp -rf $COMM_LAYER_DIR/package.json node_modules/@metamask/sdk-communication-layer/package.json +cp -rf $SDK_DIR/dist node_modules/@metamask/sdk/dist +cp -rf $SDK_DIR/package.json node_modules/@metamask/sdk/package.json + +cp -rf $SDK_REACT_DIR/dist node_modules/@metamask/sdk-react/dist +cp -rf $SDK_REACT_DIR/package.json node_modules/@metamask/sdk-react/package.json + +cp -rf $SDK_INSTALL_MODAL_WEB_DIR/dist node_modules/@metamask/sdk-install-modal-web +cp -rf $SDK_INSTALL_MODAL_WEB_DIR/package.json node_modules/@metamask/sdk-install-modal-web/package.json + +# Remove vite cache +rm -rf .next echo "All done." diff --git a/packages/examples/nextjs-demo/src/app/SDKContainer.tsx b/packages/examples/nextjs-demo/src/app/SDKContainer.tsx index fc8f65532..61c735c6d 100644 --- a/packages/examples/nextjs-demo/src/app/SDKContainer.tsx +++ b/packages/examples/nextjs-demo/src/app/SDKContainer.tsx @@ -30,7 +30,7 @@ export default function SDKContainer() { const [serviceStatus, setServiceStatus] = useState(); const [activeProvider, setActiveProvider] = useState(); const [currentLanguage, setCurrentLanguage] = useState( - localStorage.getItem('MetaMaskSDKLng') || 'en', + 'en', ); const languages = sdk?.availableLanguages ?? ['en']; diff --git a/packages/examples/nextjs-demo/yarn.lock b/packages/examples/nextjs-demo/yarn.lock index 914a70288..4340fd99b 100644 --- a/packages/examples/nextjs-demo/yarn.lock +++ b/packages/examples/nextjs-demo/yarn.lock @@ -12,6 +12,1081 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.0": + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" + dependencies: + "@jridgewell/gen-mapping": ^0.3.5 + "@jridgewell/trace-mapping": ^0.3.24 + checksum: d3ad7b89d973df059c4e8e6d7c972cbeb1bb2f18f002a3bd04ae0707da214cb06cc06929b65aa2313b9347463df2914772298bae8b1d7973f246bb3f2ab3e8f0 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.0, @babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": ^7.25.9 + js-tokens: ^4.0.0 + picocolors: ^1.0.0 + checksum: db13f5c42d54b76c1480916485e6900748bbcb0014a8aca87f50a091f70ff4e0d0a6db63cade75eb41fcc3d2b6ba0a7f89e343def4f96f00269b41b8ab8dd7b8 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.26.0, @babel/compat-data@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/compat-data@npm:7.26.5" + checksum: 7aaac0e79cf6f38478b877b1185413390bfe8ce9f2a19f906cfdf898df82f5a932579bee49c5d0d0a6fd838c715ff59d4958bfd161ef0e857e5eb083efb707b4 + languageName: node + linkType: hard + +"@babel/core@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/core@npm:7.26.0" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.26.0 + "@babel/generator": ^7.26.0 + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-module-transforms": ^7.26.0 + "@babel/helpers": ^7.26.0 + "@babel/parser": ^7.26.0 + "@babel/template": ^7.25.9 + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.26.0 + convert-source-map: ^2.0.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: b296084cfd818bed8079526af93b5dfa0ba70282532d2132caf71d4060ab190ba26d3184832a45accd82c3c54016985a4109ab9118674347a7e5e9bc464894e6 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.26.0, @babel/generator@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/generator@npm:7.26.5" + dependencies: + "@babel/parser": ^7.26.5 + "@babel/types": ^7.26.5 + "@jridgewell/gen-mapping": ^0.3.5 + "@jridgewell/trace-mapping": ^0.3.25 + jsesc: ^3.0.2 + checksum: baa42a98cd01efa3ae3634a6caa81d0738e5e0bdba4efbf1ac735216c8d7cf6bdffeab69c468e6ab2063b07db402346113def4962719746756518432f83c53ba + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" + dependencies: + "@babel/types": ^7.25.9 + checksum: 41edda10df1ae106a9b4fe617bf7c6df77db992992afd46192534f5cff29f9e49a303231733782dd65c5f9409714a529f215325569f14282046e9d3b7a1ffb6c + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/helper-compilation-targets@npm:7.26.5" + dependencies: + "@babel/compat-data": ^7.26.5 + "@babel/helper-validator-option": ^7.25.9 + browserslist: ^4.24.0 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: 6bc0107613bf1d4d21913606e8e517194e5099a24db2a8374568e56ef4626e8140f9b8f8a4aabc35479f5904459a0aead2a91ee0dc63aae110ccbc2bc4b4fda1 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-member-expression-to-functions": ^7.25.9 + "@babel/helper-optimise-call-expression": ^7.25.9 + "@babel/helper-replace-supers": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/traverse": ^7.25.9 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 91dd5f203ed04568c70b052e2f26dfaac7c146447196c00b8ecbb6d3d2f3b517abadb985d3321a19d143adaed6fe17f7f79f8f50e0c20e9d8ad83e1027b42424 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.26.3" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + regexpu-core: ^6.2.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 50a27d8ce6da5c2fa0c62c132c4d27cfeb36e3233ff1e5220d643de3dafe49423b507382f0b72a696fce7486014b134c1e742f55438590f9405d26765b009af0 + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.6.2, @babel/helper-define-polyfill-provider@npm:^0.6.3": + version: 0.6.3 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.3" + dependencies: + "@babel/helper-compilation-targets": ^7.22.6 + "@babel/helper-plugin-utils": ^7.22.5 + debug: ^4.1.1 + lodash.debounce: ^4.0.8 + resolve: ^1.14.2 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 710e6d8a5391736b9f53f09d0494575c2e03de199ad8d1349bc8e514cb85251ea1f1842c2ff44830849d482052ddb42ae931101002a87a263b12f649c2e57c01 + languageName: node + linkType: hard + +"@babel/helper-import-to-platform-api@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-import-to-platform-api@npm:7.25.9" + dependencies: + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-module-imports": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2579311be1f815af1f82d5cc3918105a0414b0d96a7572e2aabaf9145cb8565184375c71c1b0e2750f0e81a361cdc09f3c2758d65c7e8f1f44ba1a287aebe89a + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" + dependencies: + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 8e2f1979b6d596ac2a8cbf17f2cf709180fefc274ac3331408b48203fe19134ed87800774ef18838d0275c3965130bae22980d90caed756b7493631d4b2cf961 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-module-imports@npm:7.25.9" + dependencies: + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 1b411ce4ca825422ef7065dffae7d8acef52023e51ad096351e3e2c05837e9bf9fca2af9ca7f28dc26d596a588863d0fedd40711a88e350b736c619a80e704e6 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.25.9, @babel/helper-module-transforms@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helper-module-transforms@npm:7.26.0" + dependencies: + "@babel/helper-module-imports": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 942eee3adf2b387443c247a2c190c17c4fd45ba92a23087abab4c804f40541790d51ad5277e4b5b1ed8d5ba5b62de73857446b7742f835c18ebd350384e63917 + languageName: node + linkType: hard + +"@babel/helper-optimise-call-expression@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" + dependencies: + "@babel/types": ^7.25.9 + checksum: f09d0ad60c0715b9a60c31841b3246b47d67650c512ce85bbe24a3124f1a4d66377df793af393273bc6e1015b0a9c799626c48e53747581c1582b99167cc65dc + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/helper-plugin-utils@npm:7.26.5" + checksum: 4771fbb1711c624c62d12deabc2ed7435a6e6994b6ce09d5ede1bc1bf19be59c3775461a1e693bdd596af865685e87bb2abc778f62ceadc1b2095a8e2aa74180 + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-remap-async-to-generator@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-wrap-function": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: ea37ad9f8f7bcc27c109963b8ebb9d22bac7a5db2a51de199cb560e251d5593fe721e46aab2ca7d3e7a24b0aa4aff0eaf9c7307af9c2fd3a1d84268579073052 + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/helper-replace-supers@npm:7.26.5" + dependencies: + "@babel/helper-member-expression-to-functions": ^7.25.9 + "@babel/helper-optimise-call-expression": ^7.25.9 + "@babel/traverse": ^7.26.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: c5ab31b29c7cc09e30278f8860ecdb873ce6c84b5c08bc5239c369c7c4fe9f0a63cda61b55b7bbd20edb4e5dc32e73087cc3c57d85264834bd191551d1499185 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" + dependencies: + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: fdbb5248932198bc26daa6abf0d2ac42cab9c2dbb75b7e9f40d425c8f28f09620b886d40e7f9e4e08ffc7aaa2cefe6fc2c44be7c20e81f7526634702fb615bdc + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 6435ee0849e101681c1849868278b5aee82686ba2c1e27280e5e8aca6233af6810d39f8e4e693d2f2a44a3728a6ccfd66f72d71826a94105b86b731697cdfa99 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 5b85918cb1a92a7f3f508ea02699e8d2422fe17ea8e82acd445006c0ef7520fbf48e3dbcdaf7b0a1d571fc3a2715a29719e5226636cb6042e15fe6ed2a590944 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-option@npm:7.25.9" + checksum: 9491b2755948ebbdd68f87da907283698e663b5af2d2b1b02a2765761974b1120d5d8d49e9175b167f16f72748ffceec8c9cf62acfbee73f4904507b246e2b3d + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-wrap-function@npm:7.25.9" + dependencies: + "@babel/template": ^7.25.9 + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 8ec1701e60ae004415800c4a7a188f5564c73b4e4f3fdf58dd3f34a3feaa9753173f39bbd6d02e7ecc974f48155efc7940e62584435b3092c07728ee46a604ea + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/helpers@npm:7.26.0" + dependencies: + "@babel/template": ^7.25.9 + "@babel/types": ^7.26.0 + checksum: d77fe8d45033d6007eadfa440355c1355eed57902d5a302f450827ad3d530343430a21210584d32eef2f216ae463d4591184c6fc60cf205bbf3a884561469200 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/parser@npm:7.26.5" + dependencies: + "@babel/types": ^7.26.5 + bin: + parser: ./bin/babel-parser.js + checksum: 663aebf27c1dc04813e6c1d6e8e8fcb2954163ec297a95bdb3f1d0c2a0f04b504bddc09588fe4b176b43fad28c8a4b2914838a1edffdd426537a42f3ac644f1e + languageName: node + linkType: hard + +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: b33d37dacf98a9c74f53959999adc37a258057668b62dba557e6865689433c53764673109eaba9102bf73b2ac4db162f0d9b89a6cca6f1b71d12f5908ec11da9 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: d3e14ab1cb9cb50246d20cab9539f2fbd1e7ef1ded73980c8ad7c0561b4d5e0b144d362225f0976d47898e04cbd40f2000e208b0913bd788346cf7791b96af91 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a9d1ee3fd100d3eb6799a2f2bbd785296f356c531d75c9369f71541811fa324270258a374db103ce159156d006da2f33370330558d0133e6f7584152c34997ca + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/plugin-transform-optional-chaining": ^7.25.9 + peerDependencies: + "@babel/core": ^7.13.0 + checksum: 5b298b28e156f64de51cdb03a2c5b80c7f978815ef1026f3ae8b9fc48d28bf0a83817d8fbecb61ef8fb94a7201f62cca5103cc6e7b9e8f28e38f766d7905b378 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: c684593952ab1b40dfa4e64e98a07e7227c6db175c21bd0e6d71d2ad5d240fef4e4a984d56f05a494876542a022244fe1c1098f4116109fd90d06615e8a269b1 + languageName: node + linkType: hard + +"@babel/plugin-proposal-json-modules@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-proposal-json-modules@npm:7.25.9" + dependencies: + "@babel/helper-import-to-platform-api": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/plugin-syntax-import-attributes": ^7.25.9 + peerDependencies: + "@babel/core": ^7.22.0 + checksum: fcf0be3c5b0a872781b67e5d45878f0a81022361385f0d76d81f2e4f50161cd856c621791763d41fe5795c0c1ff9b07392d2e7fc03bb1539e5658671dbb14042 + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": + version: 7.21.0-placeholder-for-preset-env.2 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d97745d098b835d55033ff3a7fb2b895b9c5295b08a5759e4f20df325aa385a3e0bc9bd5ad8f2ec554a44d4e6525acfc257b8c5848a1345cb40f26a30e277e91 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.26.0" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b58f2306df4a690ca90b763d832ec05202c50af787158ff8b50cdf3354359710bce2e1eb2b5135fcabf284756ac8eadf09ca74764aa7e76d12a5cac5f6b21e67 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.25.9, @babel/plugin-syntax-import-attributes@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.26.0" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c122aa577166c80ee67f75aebebeef4150a132c4d3109d25d7fc058bf802946f883e330f20b78c1d3e3a5ada631c8780c263d2d01b5dbaecc69efefeedd42916 + languageName: node + linkType: hard + +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.18.6 + "@babel/helper-plugin-utils": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: c29f081224859483accf55fb4d091db2aac0dcd0d7954bac5ca889030cc498d3f771aa20eb2e9cd8310084ec394d85fa084b97faf09298b6bc9541182b3eb5bb + languageName: node + linkType: hard + +"@babel/plugin-transform-async-generator-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-remap-async-to-generator": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 41e02c18c2a57de9f274fa2c5a1bf81a20ab5f321db29cc3051512b9c5bdf3f1a8c42f1fc282cb62343c6d50849f992eede954d5f7fb5e7df48ae0c59ea7e054 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.25.9" + dependencies: + "@babel/helper-module-imports": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-remap-async-to-generator": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b3ad50fb93c171644d501864620ed23952a46648c4df10dc9c62cc9ad08031b66bd272cfdd708faeee07c23b6251b16f29ce0350473e4c79f0c32178d38ce3a6 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.25.9": + version: 7.26.5 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.26.5" + dependencies: + "@babel/helper-plugin-utils": ^7.26.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f2046c09bf8e588bfb1a6342d0eee733189102cf663ade27adb0130f3865123af5816b40a55ec8d8fa09271b54dfdaf977cd2f8e0b3dc97f18e690188d5a2174 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e869500cfb1995e06e64c9608543b56468639809febfcdd6fcf683bc0bf1be2431cacf2981a168a1a14f4766393e37bc9f7c96d25bc5b5f39a64a8a8ad0bf8e0 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-properties@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-class-properties@npm:7.25.9" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8d69e2c285486b63f49193cbcf7a15e1d3a5f632c1c07d7a97f65306df7f554b30270b7378dde143f8b557d1f8f6336c643377943dec8ec405e4cd11e90b9ea + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/plugin-transform-class-static-block@npm:7.26.0" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.12.0 + checksum: d779d4d3a6f8d363f67fcbd928c15baa72be8d3b86c6d05e0300b50e66e2c4be9e99398b803d13064bc79d90ae36e37a505e3dc8af11904459804dec07660246 + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-classes@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-replace-supers": ^7.25.9 + "@babel/traverse": ^7.25.9 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d12584f72125314cc0fa8c77586ece2888d677788ac75f7393f5da574dfe4e45a556f7e3488fab29c8777ab3e5856d7a2d79f6df02834083aaa9d766440e3c68 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-computed-properties@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/template": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f77fa4bc0c1e0031068172df28852388db6b0f91c268d037905f459607cf1e8ebab00015f9f179f4ad96e11c5f381b635cd5dc4e147a48c7ac79d195ae7542de + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-destructuring@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 965f63077a904828f4adee91393f83644098533442b8217d5a135c23a759a4c252c714074c965676a60d2c33f610f579a4eeb59ffd783724393af61c0ca45fef + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8bdf1bb9e6e3a2cc8154ae88a3872faa6dc346d6901994505fb43ac85f858728781f1219f40b67f7bb0687c507450236cb7838ac68d457e65637f98500aa161b + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b553eebc328797ead6be5ba5bdaf2f1222cea8a5bd33fb4ed625975d4f9b510bfb0d688d97e314cd4b4a48b279bea7b3634ad68c1b41ee143c3082db0ae74037 + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: f7233cf596be8c6843d31951afaf2464a62a610cb89c72c818c044765827fab78403ab8a7d3a6386f838c8df574668e2a48f6c206b1d7da965aff9c6886cb8e6 + languageName: node + linkType: hard + +"@babel/plugin-transform-dynamic-import@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: aaca1ccda819be9b2b85af47ba08ddd2210ff2dbea222f26e4cd33f97ab020884bf81a66197e50872721e9daf36ceb5659502c82199884ea74d5d75ecda5c58b + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.26.3" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b369ffad07e02e259c43a09d309a5ca86cb9da6b43b1df6256463a810b172cedc4254742605eec0fc2418371c3f7430430f5abd36f21717281e79142308c13ba + languageName: node + linkType: hard + +"@babel/plugin-transform-export-namespace-from@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4dfe8df86c5b1d085d591290874bb2d78a9063090d71567ed657a418010ad333c3f48af2c974b865f53bbb718987a065f89828d43279a7751db1a56c9229078d + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-for-of@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 41b56e70256a29fc26ed7fb95ece062d7ec2f3b6ea8f0686349ffd004cd4816132085ee21165b89c502ee7161cb7cfb12510961638851357945dc7bc546475b7 + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-function-name@npm:7.25.9" + dependencies: + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8d7c8d019a6eb57eab5ca1be3e3236f175557d55b1f3b11f8ad7999e3fbb1cf37905fd8cb3a349bffb4163a558e9f33b63f631597fdc97c858757deac1b2fd7 + languageName: node + linkType: hard + +"@babel/plugin-transform-json-strings@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-json-strings@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e2498d84761cfd05aaea53799933d55af309c9d6204e66b38778792d171e4d1311ad34f334259a3aa3407dd0446f6bd3e390a1fcb8ce2e42fe5aabed0e41bee1 + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3cca75823a38aab599bc151b0fa4d816b5e1b62d6e49c156aa90436deb6e13649f5505973151a10418b64f3f9d1c3da53e38a186402e0ed7ad98e482e70c0c14 + languageName: node + linkType: hard + +"@babel/plugin-transform-logical-assignment-operators@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8c6febb4ac53852314d28b5e2c23d5dbbff7bf1e57d61f9672e0d97531ef7778b3f0ad698dcf1179f5486e626c77127508916a65eb846a89e98a92f70ed3537b + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: db92041ae87b8f59f98b50359e0bb172480f6ba22e5e76b13bdfe07122cbf0daa9cd8ad2e78dcb47939938fed88ad57ab5989346f64b3a16953fc73dea3a9b1f + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-modules-amd@npm:7.25.9" + dependencies: + "@babel/helper-module-transforms": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: baad1f6fd0e0d38e9a9c1086a06abdc014c4c653fd452337cadfe23fb5bd8bf4368d1bc433a5ac8e6421bc0732ebb7c044cf3fb39c1b7ebe967d66e26c4e5cec + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.25.9, @babel/plugin-transform-modules-commonjs@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.26.3" + dependencies: + "@babel/helper-module-transforms": ^7.26.0 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0ac9aa4e5fe9fe34b58ee174881631e5e1c89eee5b1ebfd1147934686be92fc5fbfdc11119f0b607b3743d36a1cbcb7c36f18e0dd4424d6d7b749b1b9a18808a + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.9" + dependencies: + "@babel/helper-module-transforms": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: bf446202f372ba92dc0db32b24b56225b6e3ad3b227e31074de8b86fdec01c273ae2536873e38dbe3ceb1cd0894209343adeaa37df208e3fa88c0c7dffec7924 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-modules-umd@npm:7.25.9" + dependencies: + "@babel/helper-module-transforms": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 946db66be5f04ab9ee56c424b00257276ec094aa2f148508927e6085239f76b00304fa1e33026d29eccdbe312efea15ca3d92e74a12689d7f0cdd9a7ba1a6c54 + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 434346ba05cf74e3f4704b3bdd439287b95cd2a8676afcdc607810b8c38b6f4798cd69c1419726b2e4c7204e62e4a04d31b0360e91ca57a930521c9211e07789 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-new-target@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f8113539919aafce52f07b2bd182c771a476fe1d5d96d813460b33a16f173f038929369c595572cadc1f7bd8cb816ce89439d056e007770ddd7b7a0878e7895f + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.25.9": + version: 7.26.6 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.26.6" + dependencies: + "@babel/helper-plugin-utils": ^7.26.5 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 752837d532b85c41f6bb868e83809605f513bc9a3b8e88ac3d43757c9bf839af4f246874c1c6d6902bb2844d355efccae602c3856098911f8abdd603672f8379 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0528ef041ed88e8c3f51624ee87b8182a7f246fe4013f0572788e0727d20795b558f2b82e3989b5dd416cbd339500f0d88857de41b6d3b6fdacb1d5344bcc5b1 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.25.9" + dependencies: + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/plugin-transform-parameters": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8ff73e1c46a03056b3a2236bafd6b3a4b83da93afe7ee24a50d0a8088150bf85bc5e5977daa04e66ff5fb7613d02d63ad49b91ebb64cf3f3022598d722e3a7a + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-object-super@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-replace-supers": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1817b5d8b80e451ae1ad9080cca884f4f16df75880a158947df76a2ed8ab404d567a7dce71dd8051ef95f90fbe3513154086a32aba55cc76027f6cbabfbd7f98 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b46a8d1e91829f3db5c252583eb00d05a779b4660abeea5500fda0f8ffa3584fd18299443c22f7fddf0ed9dfdb73c782c43b445dc468d4f89803f2356963b406 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f1642a7094456067e82b176e1e9fd426fda7ed9df54cb6d10109fc512b622bf4b3c83acc5875125732b8622565107fdbe2d60fe3ec8685e1d1c22c38c1b57782 + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-parameters@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d7ba2a7d05edbc85aed741289b0ff3d6289a1c25d82ac4be32c565f88a66391f46631aad59ceeed40824037f7eeaa7a0de1998db491f50e65a565cd964f78786 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-private-methods@npm:7.25.9" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 6e3671b352c267847c53a170a1937210fa8151764d70d25005e711ef9b21969aaf422acc14f9f7fb86bc0e4ec43e7aefcc0ad9196ae02d262ec10f509f126a58 + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-create-class-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9ce3e983fea9b9ba677c192aa065c0b42ebdc7774be4c02135df09029ad92a55c35b004650c75952cb64d650872ed18f13ab64422c6fc891d06333762caa8a0a + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-property-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 436046ab07d54a9b44a384eeffec701d4e959a37a7547dda72e069e751ca7ff753d1782a8339e354b97c78a868b49ea97bf41bf5a44c6d7a3c0a05ad40eeb49c + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-regenerator@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + regenerator-transform: ^0.15.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1c09e8087b476c5967282c9790fb8710e065eda77c60f6cb5da541edd59ded9d003d96f8ef640928faab4a0b35bf997673499a194973da4f0c97f0935807a482 + languageName: node + linkType: hard + +"@babel/plugin-transform-regexp-modifiers@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/plugin-transform-regexp-modifiers@npm:7.26.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 726deca486bbd4b176f8a966eb0f4aabc19d9def3b8dabb8b3a656778eca0df1fda3f3c92b213aa5a184232fdafd5b7bd73b4e24ca4345c498ef6baff2bda4e1 + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-reserved-words@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8beda04481b25767acbd1f6b9ef7b3a9c12fbd9dcb24df45a6ad120e1dc4b247c073db60ac742f9093657d6d8c050501fc0606af042f81a3bb6a3ff862cddc47 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f774995d58d4e3a992b732cf3a9b8823552d471040e280264dd15e0735433d51b468fef04d75853d061309389c66bda10ce1b298297ce83999220eb0ad62741d + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-spread@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2403a5d49171b7714d5e5ecb1f598c61575a4dbe5e33e5a5f08c0ea990b75e693ca1ea983b6a96b2e3e5e7da48c8238333f525e47498c53b577c5d094d964c06 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7454b00844dbe924030dd15e2b3615b36e196500c4c47e98dabc6b37a054c5b1038ecd437e910aabf0e43bf56b973cb148d3437d50f6e2332d8309568e3e979b + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-template-literals@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 92eb1d6e2d95bd24abbb74fa7640d02b66ff6214e0bb616d7fda298a7821ce15132a4265d576a3502a347a3c9e94b6c69ed265bb0784664592fa076785a3d16a + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 3f9458840d96f61502f0e9dfaae3efe8325fa0b2151e24ea0d41307f28cdd166905419f5a43447ce0f1ae4bfd001f3906b658839a60269c254168164090b4c73 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.25.9" + dependencies: + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: be067e07488d804e3e82d7771f23666539d2ae5af03bf6eb8480406adf3dabd776e60c1fd5c6078dc5714b73cd80bbaca70e71d4f5d154c5c57200581602ca2f + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 201f6f46c1beb399e79aa208b94c5d54412047511795ce1e790edcd189cef73752e6a099fdfc01b3ad12205f139ae344143b62f21f44bbe02338a95e8506a911 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e8baae867526e179467c6ef5280d70390fa7388f8763a19a27c21302dd59b121032568be080749514b097097ceb9af716bf4b90638f1b3cf689aa837ba20150f + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 4445ef20de687cb4dcc95169742a8d9013d680aa5eee9186d8e25875bbfa7ee5e2de26a91177ccf70b1db518e36886abcd44750d28db5d7a9539f0efa6839f4b + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.26.0": + version: 7.26.0 + resolution: "@babel/preset-env@npm:7.26.0" + dependencies: + "@babel/compat-data": ^7.26.0 + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-validator-option": ^7.25.9 + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": ^7.25.9 + "@babel/plugin-bugfix-safari-class-field-initializer-scope": ^7.25.9 + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.25.9 + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": ^7.25.9 + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": ^7.25.9 + "@babel/plugin-proposal-private-property-in-object": 7.21.0-placeholder-for-preset-env.2 + "@babel/plugin-syntax-import-assertions": ^7.26.0 + "@babel/plugin-syntax-import-attributes": ^7.26.0 + "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 + "@babel/plugin-transform-arrow-functions": ^7.25.9 + "@babel/plugin-transform-async-generator-functions": ^7.25.9 + "@babel/plugin-transform-async-to-generator": ^7.25.9 + "@babel/plugin-transform-block-scoped-functions": ^7.25.9 + "@babel/plugin-transform-block-scoping": ^7.25.9 + "@babel/plugin-transform-class-properties": ^7.25.9 + "@babel/plugin-transform-class-static-block": ^7.26.0 + "@babel/plugin-transform-classes": ^7.25.9 + "@babel/plugin-transform-computed-properties": ^7.25.9 + "@babel/plugin-transform-destructuring": ^7.25.9 + "@babel/plugin-transform-dotall-regex": ^7.25.9 + "@babel/plugin-transform-duplicate-keys": ^7.25.9 + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": ^7.25.9 + "@babel/plugin-transform-dynamic-import": ^7.25.9 + "@babel/plugin-transform-exponentiation-operator": ^7.25.9 + "@babel/plugin-transform-export-namespace-from": ^7.25.9 + "@babel/plugin-transform-for-of": ^7.25.9 + "@babel/plugin-transform-function-name": ^7.25.9 + "@babel/plugin-transform-json-strings": ^7.25.9 + "@babel/plugin-transform-literals": ^7.25.9 + "@babel/plugin-transform-logical-assignment-operators": ^7.25.9 + "@babel/plugin-transform-member-expression-literals": ^7.25.9 + "@babel/plugin-transform-modules-amd": ^7.25.9 + "@babel/plugin-transform-modules-commonjs": ^7.25.9 + "@babel/plugin-transform-modules-systemjs": ^7.25.9 + "@babel/plugin-transform-modules-umd": ^7.25.9 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.25.9 + "@babel/plugin-transform-new-target": ^7.25.9 + "@babel/plugin-transform-nullish-coalescing-operator": ^7.25.9 + "@babel/plugin-transform-numeric-separator": ^7.25.9 + "@babel/plugin-transform-object-rest-spread": ^7.25.9 + "@babel/plugin-transform-object-super": ^7.25.9 + "@babel/plugin-transform-optional-catch-binding": ^7.25.9 + "@babel/plugin-transform-optional-chaining": ^7.25.9 + "@babel/plugin-transform-parameters": ^7.25.9 + "@babel/plugin-transform-private-methods": ^7.25.9 + "@babel/plugin-transform-private-property-in-object": ^7.25.9 + "@babel/plugin-transform-property-literals": ^7.25.9 + "@babel/plugin-transform-regenerator": ^7.25.9 + "@babel/plugin-transform-regexp-modifiers": ^7.26.0 + "@babel/plugin-transform-reserved-words": ^7.25.9 + "@babel/plugin-transform-shorthand-properties": ^7.25.9 + "@babel/plugin-transform-spread": ^7.25.9 + "@babel/plugin-transform-sticky-regex": ^7.25.9 + "@babel/plugin-transform-template-literals": ^7.25.9 + "@babel/plugin-transform-typeof-symbol": ^7.25.9 + "@babel/plugin-transform-unicode-escapes": ^7.25.9 + "@babel/plugin-transform-unicode-property-regex": ^7.25.9 + "@babel/plugin-transform-unicode-regex": ^7.25.9 + "@babel/plugin-transform-unicode-sets-regex": ^7.25.9 + "@babel/preset-modules": 0.1.6-no-external-plugins + babel-plugin-polyfill-corejs2: ^0.4.10 + babel-plugin-polyfill-corejs3: ^0.10.6 + babel-plugin-polyfill-regenerator: ^0.6.1 + core-js-compat: ^3.38.1 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0c3e2b3758cc0347dcf5551b5209db702764183dce66ff20bffceff6486c090bef9175f5f7d1e68cfe5584f0d817b2aab25ab5992058a7998f061f244c8caf5f + languageName: node + linkType: hard + +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@babel/types": ^7.4.4 + esutils: ^2.0.2 + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.19.4": version: 7.23.2 resolution: "@babel/runtime@npm:7.23.2" @@ -39,6 +1114,51 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.8.4": + version: 7.26.0 + resolution: "@babel/runtime@npm:7.26.0" + dependencies: + regenerator-runtime: ^0.14.0 + checksum: c8e2c0504ab271b3467a261a8f119bf2603eb857a0d71e37791f4e3fae00f681365073cc79f141ddaa90c6077c60ba56448004ad5429d07ac73532be9f7cf28a + languageName: node + linkType: hard + +"@babel/template@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" + dependencies: + "@babel/code-frame": ^7.25.9 + "@babel/parser": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 103641fea19c7f4e82dc913aa6b6ac157112a96d7c724d513288f538b84bae04fb87b1f1e495ac1736367b1bc30e10f058b30208fb25f66038e1f1eb4e426472 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.25.9, @babel/traverse@npm:^7.26.5": + version: 7.26.5 + resolution: "@babel/traverse@npm:7.26.5" + dependencies: + "@babel/code-frame": ^7.26.2 + "@babel/generator": ^7.26.5 + "@babel/parser": ^7.26.5 + "@babel/template": ^7.25.9 + "@babel/types": ^7.26.5 + debug: ^4.3.1 + globals: ^11.1.0 + checksum: 28f28037ec6bb72ded695b2bd79c373f13dc993a408c6037c3d46a1234360342a688c031f9ed4fc8528183892a63b54edce0b516e723fb3dffd606da75496cdc + languageName: node + linkType: hard + +"@babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.26.5, @babel/types@npm:^7.4.4": + version: 7.26.5 + resolution: "@babel/types@npm:7.26.5" + dependencies: + "@babel/helper-string-parser": ^7.25.9 + "@babel/helper-validator-identifier": ^7.25.9 + checksum: 65dc14aa32ace22655c5edadeb99df80776c09cd93c105feaf49cc0583f3116aff0581b7eab630888c39ba61151f251c1399ec982b93585b0d1d1bf4a45b54f9 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -162,6 +1282,59 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.8 + resolution: "@jridgewell/gen-mapping@npm:0.3.8" + dependencies: + "@jridgewell/set-array": ^1.2.1 + "@jridgewell/sourcemap-codec": ^1.4.10 + "@jridgewell/trace-mapping": ^0.3.24 + checksum: c0687b5227461717aa537fe71a42e356bcd1c43293b3353796a148bf3b0d6f59109def46c22f05b60e29a46f19b2e4676d027959a7c53a6c92b9d5b0d87d0420 + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 83b85f72c59d1c080b4cbec0fef84528963a1b5db34e4370fa4bd1e3ff64a0d80e0cee7369d11d73c704e0286fb2865b530acac7a871088fbe92b5edf1000870 + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 832e513a85a588f8ed4f27d1279420d8547743cc37fcad5a5a76fc74bb895b013dfe614d0eed9cb860048e6546b798f8f2652020b4b2ba0561b05caa8c654b10 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 05df4f2538b3b0f998ea4c1cd34574d0feba216fa5d4ccaef0187d12abf82eafe6021cec8b49f9bb4d90f2ba4582ccc581e72986a5fcf4176ae0cfeb04cf52ec + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: 9d3c40d225e139987b50c48988f8717a54a8c994d8a948ee42e1412e08988761d0754d7d10b803061cc3aebf35f92a5dbbab493bd0e1a9ef9e89a2130e83ba34 + languageName: node + linkType: hard + +"@metamask/json-rpc-engine@npm:^10.0.2": + version: 10.0.2 + resolution: "@metamask/json-rpc-engine@npm:10.0.2" + dependencies: + "@metamask/rpc-errors": ^7.0.2 + "@metamask/safe-event-emitter": ^3.0.0 + "@metamask/utils": ^11.0.1 + checksum: db561d6ffe4de041dc2fe79c6d1eb098bd9eb444864568c4781f3227e6c7e33563ac2858caadb14f6b58facbf189fe0f50725adbc29f3b2641b787e550e548e6 + languageName: node + linkType: hard + "@metamask/json-rpc-engine@npm:^8.0.1, @metamask/json-rpc-engine@npm:^8.0.2": version: 8.0.2 resolution: "@metamask/json-rpc-engine@npm:8.0.2" @@ -185,6 +1358,18 @@ __metadata: languageName: node linkType: hard +"@metamask/json-rpc-middleware-stream@npm:^8.0.6": + version: 8.0.6 + resolution: "@metamask/json-rpc-middleware-stream@npm:8.0.6" + dependencies: + "@metamask/json-rpc-engine": ^10.0.2 + "@metamask/safe-event-emitter": ^3.0.0 + "@metamask/utils": ^11.0.1 + readable-stream: ^3.6.2 + checksum: e004de7a8090afc0441b9bf661106ac07a550862f6e824bfebcb14b46eea7551beeaeab4c39ac810beee0f53ad1032344a99eef1c0f5f118fe8d388e7e0c5014 + languageName: node + linkType: hard + "@metamask/object-multiplex@npm:^2.0.0": version: 2.0.0 resolution: "@metamask/object-multiplex@npm:2.0.0" @@ -224,6 +1409,27 @@ __metadata: languageName: node linkType: hard +"@metamask/providers@npm:^18.3.1": + version: 18.3.1 + resolution: "@metamask/providers@npm:18.3.1" + dependencies: + "@metamask/json-rpc-engine": ^10.0.2 + "@metamask/json-rpc-middleware-stream": ^8.0.6 + "@metamask/object-multiplex": ^2.0.0 + "@metamask/rpc-errors": ^7.0.2 + "@metamask/safe-event-emitter": ^3.1.1 + "@metamask/utils": ^11.0.1 + detect-browser: ^5.2.0 + extension-port-stream: ^4.1.0 + fast-deep-equal: ^3.1.3 + is-stream: ^2.0.0 + readable-stream: ^3.6.2 + peerDependencies: + webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 + checksum: 626112e3bdaa3b63c041ac0d280777419109a1ed2a6cdd50c1b3c7700c53d2e342f93748244a58a74d2e94357fe9eed1137317acff4df9ee0586798e02cfe00d + languageName: node + linkType: hard + "@metamask/rpc-errors@npm:^6.2.1": version: 6.2.1 resolution: "@metamask/rpc-errors@npm:6.2.1" @@ -234,14 +1440,17 @@ __metadata: languageName: node linkType: hard -"@metamask/safe-event-emitter@npm:^3.0.0": - version: 3.0.0 - resolution: "@metamask/safe-event-emitter@npm:3.0.0" - checksum: 8dc58a76f9f75bf2405931465fc311c68043d851e6b8ebe9f82ae339073a08a83430dba9338f8e3adc4bfc8067607125074bcafa32baee3a5157f42343dc89e5 +"@metamask/rpc-errors@npm:^7.0.2": + version: 7.0.2 + resolution: "@metamask/rpc-errors@npm:7.0.2" + dependencies: + "@metamask/utils": ^11.0.1 + fast-safe-stringify: ^2.0.6 + checksum: 262a1ab57121e277eb979325d8e4335b9f4194c5acd0138ee0032db35b4e20ea0423badb5dad4bdf6abb85d22b476377f17911a54f82b3b1a2bdffc36654d028 languageName: node linkType: hard -"@metamask/safe-event-emitter@npm:^3.1.1": +"@metamask/safe-event-emitter@npm:3.1.1": version: 3.1.1 resolution: "@metamask/safe-event-emitter@npm:3.1.1" checksum: e24db4d7c20764bfc5b025065f92518c805f0ffb1da4820078b8cff7dcae964c0f354cf053fcb7ac659de015d5ffdf21aae5e8d44e191ee8faa9066855f22653 @@ -354,6 +1563,30 @@ __metadata: languageName: node linkType: hard +"@metamask/superstruct@npm:^3.1.0": + version: 3.1.0 + resolution: "@metamask/superstruct@npm:3.1.0" + checksum: 00e4d0c0aae8b25ccc1885c1db0bb4ed1590010570140c255e4deee3bf8a10c859c8fce5e475b4ae09c8a56316207af87585b91f7f5a5c028d668ccd111f19e3 + languageName: node + linkType: hard + +"@metamask/utils@npm:^11.0.1": + version: 11.0.1 + resolution: "@metamask/utils@npm:11.0.1" + dependencies: + "@ethereumjs/tx": ^4.2.0 + "@metamask/superstruct": ^3.1.0 + "@noble/hashes": ^1.3.1 + "@scure/base": ^1.1.3 + "@types/debug": ^4.1.7 + debug: ^4.3.4 + pony-cause: ^2.1.10 + semver: ^7.5.4 + uuid: ^9.0.1 + checksum: a5072f87157f6763328767bf1ddc01deb94e13f32af58d0993e0450e7e211fb29882280a1013cbdc7752b152a662be3d9beef8129a9097dba7d465389c398b3c + languageName: node + linkType: hard + "@metamask/utils@npm:^8.3.0": version: 8.3.0 resolution: "@metamask/utils@npm:8.3.0" @@ -603,6 +1836,13 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:^7.0.9": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 + languageName: node + linkType: hard + "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" @@ -834,6 +2074,31 @@ __metadata: languageName: node linkType: hard +"ajv-formats@npm:^2.1.1": + version: 2.1.1 + resolution: "ajv-formats@npm:2.1.1" + dependencies: + ajv: ^8.0.0 + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + checksum: 4a287d937f1ebaad4683249a4c40c0fa3beed30d9ddc0adba04859026a622da0d317851316ea64b3680dc60f5c3c708105ddd5d5db8fe595d9d0207fd19f90b7 + languageName: node + linkType: hard + +"ajv-keywords@npm:^5.1.0": + version: 5.1.0 + resolution: "ajv-keywords@npm:5.1.0" + dependencies: + fast-deep-equal: ^3.1.3 + peerDependencies: + ajv: ^8.8.2 + checksum: c35193940b853119242c6757787f09ecf89a2c19bcd36d03ed1a615e710d19d450cb448bfda407b939aba54b002368c8bff30529cc50a0536a8e10bcce300421 + languageName: node + linkType: hard + "ajv@npm:^6.10.0, ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -846,6 +2111,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.0.0, ajv@npm:^8.9.0": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: ^3.1.3 + fast-uri: ^3.0.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + checksum: 1797bf242cfffbaf3b870d13565bd1716b73f214bb7ada9a497063aada210200da36e3ed40237285f3255acc4feeae91b1fb183625331bad27da95973f7253d9 + languageName: node + linkType: hard + "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" @@ -1053,6 +2330,55 @@ __metadata: languageName: node linkType: hard +"babel-loader@npm:^9.2.1": + version: 9.2.1 + resolution: "babel-loader@npm:9.2.1" + dependencies: + find-cache-dir: ^4.0.0 + schema-utils: ^4.0.0 + peerDependencies: + "@babel/core": ^7.12.0 + webpack: ">=5" + checksum: e1858d7625ad7cc8cabe6bbb8657f957041ffb1308375f359e92aa1654f413bfbb86a281bbf7cd4f7fff374d571c637b117551deac0231d779a198d4e4e78331 + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs2@npm:^0.4.10": + version: 0.4.12 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.12" + dependencies: + "@babel/compat-data": ^7.22.6 + "@babel/helper-define-polyfill-provider": ^0.6.3 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 6e6e6a8b85fec80a310ded2f5c151385e4ac59118909dd6a952e1025e4a478eb79dda45a5a6322cc2e598fd696eb07d4e2fa52418b4101f3dc370bdf8c8939ba + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.10.6": + version: 0.10.6 + resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.6.2 + core-js-compat: ^3.38.0 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: f762f29f7acca576897c63149c850f0a72babd3fb9ea436a2e36f0c339161c4b912a77828541d8188ce8a91e50965c6687120cf36071eabb1b7aa92f279e2164 + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.6.1": + version: 0.6.3 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.3" + dependencies: + "@babel/helper-define-polyfill-provider": ^0.6.3 + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: d12696e6b3f280eb78fac551619ca4389262db62c7352cd54bf679d830df8b35596eef2de77cf00db6648eada1c99d49c4f40636dbc9c335a1e5420cfef96750 + languageName: node + linkType: hard + "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" @@ -1208,6 +2534,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.24.0, browserslist@npm:^4.24.3": + version: 4.24.4 + resolution: "browserslist@npm:4.24.4" + dependencies: + caniuse-lite: ^1.0.30001688 + electron-to-chromium: ^1.5.73 + node-releases: ^2.0.19 + update-browserslist-db: ^1.1.1 + bin: + browserslist: cli.js + checksum: 64074bf6cf0a9ae3094d753270e3eae9cf925149db45d646f0bc67bacc2e46d7ded64a4e835b95f5fdcf0350f63a83c3755b32f80831f643a47f0886deb8a065 + languageName: node + linkType: hard + "buffer-es6@npm:^4.9.2, buffer-es6@npm:^4.9.3": version: 4.9.3 resolution: "buffer-es6@npm:4.9.3" @@ -1249,6 +2589,16 @@ __metadata: languageName: node linkType: hard +"bufferutil@npm:^4.0.9": + version: 4.0.9 + resolution: "bufferutil@npm:4.0.9" + dependencies: + node-gyp: latest + node-gyp-build: ^4.3.0 + checksum: 51ce9ee19bc4b72c2eb9f9a231dd95e786ca5a00a6bdfcae83f1d5cd8169301c79245ce96913066a5a1bbe45c44e95bc5a1761a18798b835585c1a05af65b209 + languageName: node + linkType: hard + "busboy@npm:1.6.0": version: 1.6.0 resolution: "busboy@npm:1.6.0" @@ -1302,6 +2652,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001688": + version: 1.0.30001695 + resolution: "caniuse-lite@npm:1.0.30001695" + checksum: 97729756cc19e9a93d46061ff11690d9a7d2facdb9c275111b19548adcba29d29638339bd6e659b7ddcb3649f17926a66a4cfb407605232f21918b70650a40be + languageName: node + linkType: hard + "chalk@npm:^4.0.0": version: 4.1.2 resolution: "chalk@npm:4.1.2" @@ -1386,6 +2743,13 @@ __metadata: languageName: node linkType: hard +"common-path-prefix@npm:^3.0.0": + version: 3.0.0 + resolution: "common-path-prefix@npm:3.0.0" + checksum: fdb3c4f54e51e70d417ccd950c07f757582de800c0678ca388aedefefc84982039f346f9fd9a1252d08d2da9e9ef4019f580a1d1d3a10da031e4bb3c924c5818 + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -1412,6 +2776,22 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 63ae9933be5a2b8d4509daca5124e20c14d023c820258e484e32dc324d34c2754e71297c94a05784064ad27615037ef677e3f0c00469fb55f409d2bb21261035 + languageName: node + linkType: hard + +"core-js-compat@npm:^3.38.0, core-js-compat@npm:^3.38.1": + version: 3.40.0 + resolution: "core-js-compat@npm:3.40.0" + dependencies: + browserslist: ^4.24.3 + checksum: 7ad00607c481ab2ded13d72be9ca5db5bbf42e221a175e905fb425e1ef520864aea28736c7283f57e9552d570eb6204bed87fbc8b9eab0fcfd9a7830dacccd43 + languageName: node + linkType: hard + "core-util-is@npm:~1.0.0": version: 1.0.3 resolution: "core-util-is@npm:1.0.3" @@ -1548,6 +2928,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.1.0, debug@npm:^4.3.1": + version: 4.4.0 + resolution: "debug@npm:4.4.0" + dependencies: + ms: ^2.1.3 + peerDependenciesMeta: + supports-color: + optional: true + checksum: fb42df878dd0e22816fc56e1fdca9da73caa85212fbe40c868b1295a6878f9101ae684f4eeef516c13acfc700f5ea07f1136954f43d4cd2d477a811144136479 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -1668,6 +3060,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.73": + version: 1.5.84 + resolution: "electron-to-chromium@npm:1.5.84" + checksum: 4bdf445aa4fd970cef45cbeec2d20ce609f746b78a0e2e0a053ac01126b3901827877e770b2a841333458a2967017796a67a28e1c9dafc4d35002e32178e4d39 + languageName: node + linkType: hard + "elliptic@npm:^6.5.3, elliptic@npm:^6.5.5": version: 6.5.5 resolution: "elliptic@npm:6.5.5" @@ -1892,6 +3291,13 @@ __metadata: languageName: node linkType: hard +"escalade@npm:^3.2.0": + version: 3.2.0 + resolution: "escalade@npm:3.2.0" + checksum: 47b029c83de01b0d17ad99ed766347b974b0d628e848de404018f3abee728e987da0d2d370ad4574aa3d5b5bfc368754fd085d69a30f8e75903486ec4b5b709e + languageName: node + linkType: hard + "escape-string-regexp@npm:2.0.0": version: 2.0.0 resolution: "escape-string-regexp@npm:2.0.0" @@ -2252,6 +3658,17 @@ __metadata: languageName: node linkType: hard +"extension-port-stream@npm:^4.1.0": + version: 4.2.0 + resolution: "extension-port-stream@npm:4.2.0" + dependencies: + readable-stream: ^3.6.2 || ^4.4.2 + peerDependencies: + webextension-polyfill: ^0.10.0 || ^0.11.0 || ^0.12.0 + checksum: 85559c82e3f3aa21462e234b30b7d53872708893664cd03f2f848af556cf0730cf2243b089efc9d40bbe9a4f73bd8fd19684db5a985329b0c4402b4f2fe26358 + languageName: node + linkType: hard + "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -2293,6 +3710,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.0.6 + resolution: "fast-uri@npm:3.0.6" + checksum: 7161ba2a7944778d679ba8e5f00d6a2bb479a2142df0982f541d67be6c979b17808f7edbb0ce78161c85035974bde3fa52b5137df31da46c0828cb629ba67c4e + languageName: node + linkType: hard + "fastq@npm:^1.6.0": version: 1.15.0 resolution: "fastq@npm:1.15.0" @@ -2320,6 +3744,16 @@ __metadata: languageName: node linkType: hard +"find-cache-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "find-cache-dir@npm:4.0.0" + dependencies: + common-path-prefix: ^3.0.0 + pkg-dir: ^7.0.0 + checksum: 52a456a80deeb27daa3af6e06059b63bdb9cc4af4d845fc6d6229887e505ba913cd56000349caa60bc3aa59dacdb5b4c37903d4ba34c75102d83cab330b70d2f + languageName: node + linkType: hard + "find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -2330,6 +3764,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:^6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: ^7.1.0 + path-exists: ^5.0.0 + checksum: 9a21b7f9244a420e54c6df95b4f6fc3941efd3c3e5476f8274eb452f6a85706e7a6a90de71353ee4f091fcb4593271a6f92810a324ec542650398f928783c280 + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.1.0 resolution: "flat-cache@npm:3.1.0" @@ -2406,6 +3850,13 @@ __metadata: languageName: node linkType: hard +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 2b0ff4ce708d99715ad14a6d1f894e2a83242e4a52ccfcefaee5e40050562e5f6dafc1adbb4ce2d4ab47279a45dc736ab91ea5042d843c3c092820dfe032efb1 + languageName: node + linkType: hard + "function.prototype.name@npm:^1.1.5": version: 1.1.6 resolution: "function.prototype.name@npm:1.1.6" @@ -2457,6 +3908,13 @@ __metadata: languageName: node linkType: hard +"gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec + languageName: node + linkType: hard + "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" @@ -2556,6 +4014,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e + languageName: node + linkType: hard + "globals@npm:^13.19.0": version: 13.21.0 resolution: "globals@npm:13.21.0" @@ -2704,6 +4169,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: ^1.1.2 + checksum: e8516f776a15149ca6c6ed2ae3110c417a00b62260e222590e54aa367cbcd6ed99122020b37b7fbdf05748df57b265e70095d7bf35a47660587619b15ffb93db + languageName: node + linkType: hard + "hmac-drbg@npm:^1.0.1": version: 1.0.1 resolution: "hmac-drbg@npm:1.0.1" @@ -2940,6 +4414,15 @@ __metadata: languageName: node linkType: hard +"is-core-module@npm:^2.16.0": + version: 2.16.1 + resolution: "is-core-module@npm:2.16.1" + dependencies: + hasown: ^2.0.2 + checksum: 6ec5b3c42d9cbf1ac23f164b16b8a140c3cec338bf8f884c076ca89950c7cc04c33e78f02b8cae7ff4751f3247e3174b2330f1fe4de194c7210deb8b1ea316a7 + languageName: node + linkType: hard + "is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" @@ -3220,7 +4703,7 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^3.0.0 || ^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 @@ -3238,6 +4721,24 @@ __metadata: languageName: node linkType: hard +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 19c94095ea026725540c0d29da33ab03144f6bcf2d4159e4833d534976e99e0c09c38cefa9a575279a51fc36b31166f8d6d05c9fe2645d5f15851d690b41f17f + languageName: node + linkType: hard + +"jsesc@npm:~3.0.2": + version: 3.0.2 + resolution: "jsesc@npm:3.0.2" + bin: + jsesc: bin/jsesc + checksum: a36d3ca40574a974d9c2063bf68c2b6141c20da8f2a36bd3279fc802563f35f0527a6c828801295bdfb2803952cf2cf387786c2c90ed564f88d5782475abfe3c + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -3252,6 +4753,13 @@ __metadata: languageName: node linkType: hard +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -3270,6 +4778,15 @@ __metadata: languageName: node linkType: hard +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + languageName: node + linkType: hard + "jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": version: 3.3.5 resolution: "jsx-ast-utils@npm:3.3.5" @@ -3429,6 +4946,22 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: ^6.0.0 + checksum: c1b653bdf29beaecb3d307dfb7c44d98a2a98a02ebe353c9ad055d1ac45d6ed4e1142563d222df9b9efebc2bcb7d4c792b507fad9e7150a04c29530b7db570f8 + languageName: node + linkType: hard + +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: a3f527d22c548f43ae31c861ada88b2637eb48ac6aa3eb56e82d44917971b8aa96fbb37aa60efea674dc4ee8c42074f90f7b1f772e9db375435f6c83a19b3bc6 + languageName: node + linkType: hard + "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" @@ -3447,6 +4980,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: ^3.0.2 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + languageName: node + linkType: hard + "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -3695,7 +5237,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:^2.0.0, ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -3790,16 +5332,25 @@ __metadata: version: 0.0.0-use.local resolution: "nextjs-demo@workspace:." dependencies: + "@babel/core": ^7.26.0 + "@babel/plugin-proposal-json-modules": ^7.25.9 + "@babel/plugin-syntax-import-assertions": ^7.26.0 + "@babel/plugin-transform-modules-commonjs": ^7.26.3 + "@babel/preset-env": ^7.26.0 + "@metamask/providers": ^18.3.1 "@metamask/sdk-react": ^0.30.0 "@types/node": 20.2.1 "@types/react": 18.2.6 "@types/react-dom": 18.2.4 + babel-loader: ^9.2.1 + bufferutil: ^4.0.9 eslint: 8.40.0 eslint-config-next: 13.4.3 next: 13.4.3 react: 18.2.0 react-dom: 18.2.0 typescript: 5.0.4 + utf-8-validate: ^6.0.5 languageName: unknown linkType: soft @@ -3869,6 +5420,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.19": + version: 2.0.19 + resolution: "node-releases@npm:2.0.19" + checksum: 917dbced519f48c6289a44830a0ca6dc944c3ee9243c468ebd8515a41c97c8b2c256edb7f3f750416bc37952cc9608684e6483c7b6c6f39f6bd8d86c52cfe658 + languageName: node + linkType: hard + "nopt@npm:^6.0.0": version: 6.0.0 resolution: "nopt@npm:6.0.0" @@ -4059,6 +5617,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: ^1.0.0 + checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + languageName: node + linkType: hard + "p-locate@npm:^5.0.0": version: 5.0.0 resolution: "p-locate@npm:5.0.0" @@ -4068,6 +5635,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: ^4.0.0 + checksum: 2bfe5234efa5e7a4e74b30a5479a193fdd9236f8f6b4d2f3f69e3d286d9a7d7ab0c118a2a50142efcf4e41625def635bd9332d6cbf9cc65d85eb0718c579ab38 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -4107,6 +5683,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 8ca842868cab09423994596eb2c5ec2a971c17d1a3cb36dbf060592c730c725cd524b9067d7d2a1e031fef9ba7bd2ac6dc5ec9fb92aa693265f7be3987045254 + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -4165,6 +5748,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + "picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -4172,6 +5762,15 @@ __metadata: languageName: node linkType: hard +"pkg-dir@npm:^7.0.0": + version: 7.0.0 + resolution: "pkg-dir@npm:7.0.0" + dependencies: + find-up: ^6.3.0 + checksum: 94298b20a446bfbbd66604474de8a0cdd3b8d251225170970f15d9646f633e056c80520dd5b4c1d1050c9fed8f6a9e5054b141c93806439452efe72e57562c03 + languageName: node + linkType: hard + "pony-cause@npm:^2.1.10": version: 2.1.10 resolution: "pony-cause@npm:2.1.10" @@ -4453,6 +6052,22 @@ __metadata: languageName: node linkType: hard +"regenerate-unicode-properties@npm:^10.2.0": + version: 10.2.0 + resolution: "regenerate-unicode-properties@npm:10.2.0" + dependencies: + regenerate: ^1.4.2 + checksum: d5c5fc13f8b8d7e16e791637a4bfef741f8d70e267d51845ee7d5404a32fa14c75b181c4efba33e4bff8b0000a2f13e9773593713dfe5b66597df4259275ce63 + languageName: node + linkType: hard + +"regenerate@npm:^1.4.2": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 3317a09b2f802da8db09aa276e469b57a6c0dd818347e05b8862959c6193408242f150db5de83c12c3fa99091ad95fb42a6db2c3329bfaa12a0ea4cbbeb30cb0 + languageName: node + linkType: hard + "regenerator-runtime@npm:^0.14.0": version: 0.14.0 resolution: "regenerator-runtime@npm:0.14.0" @@ -4460,6 +6075,15 @@ __metadata: languageName: node linkType: hard +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" + dependencies: + "@babel/runtime": ^7.8.4 + checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 + languageName: node + linkType: hard + "regexp.prototype.flags@npm:^1.5.0": version: 1.5.0 resolution: "regexp.prototype.flags@npm:1.5.0" @@ -4471,6 +6095,38 @@ __metadata: languageName: node linkType: hard +"regexpu-core@npm:^6.2.0": + version: 6.2.0 + resolution: "regexpu-core@npm:6.2.0" + dependencies: + regenerate: ^1.4.2 + regenerate-unicode-properties: ^10.2.0 + regjsgen: ^0.8.0 + regjsparser: ^0.12.0 + unicode-match-property-ecmascript: ^2.0.0 + unicode-match-property-value-ecmascript: ^2.1.0 + checksum: 67d3c4a3f6c99bc80b5d690074a27e6f675be1c1739f8a9acf028fbc36f1a468472574ea65e331e217995198ba4404d7878f3cb3739a73552dd3c70d3fb7f8e6 + languageName: node + linkType: hard + +"regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "regjsgen@npm:0.8.0" + checksum: a1d925ff14a4b2be774e45775ee6b33b256f89c42d480e6d85152d2133f18bd3d6af662161b226fa57466f7efec367eaf7ccd2a58c0ec2a1306667ba2ad07b0d + languageName: node + linkType: hard + +"regjsparser@npm:^0.12.0": + version: 0.12.0 + resolution: "regjsparser@npm:0.12.0" + dependencies: + jsesc: ~3.0.2 + bin: + regjsparser: bin/parser + checksum: 094b55b0ab3e1fd58f8ce5132a1d44dab08d91f7b0eea4132b0157b303ebb8ded20a9cbd893d25402d2aeddb23fac1f428ab4947b295d6fa51dd1c334a9e76f0 + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -4478,6 +6134,13 @@ __metadata: languageName: node linkType: hard +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b + languageName: node + linkType: hard + "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -4492,6 +6155,19 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.14.2": + version: 1.22.10 + resolution: "resolve@npm:1.22.10" + dependencies: + is-core-module: ^2.16.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: ab7a32ff4046fcd7c6fdd525b24a7527847d03c3650c733b909b01b757f92eb23510afa9cc3e9bf3f26a3e073b48c88c706dfd4c1d2fb4a16a96b73b6328ddcf + languageName: node + linkType: hard + "resolve@npm:^1.22.4": version: 1.22.4 resolution: "resolve@npm:1.22.4" @@ -4518,6 +6194,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@^1.14.2#~builtin": + version: 1.22.10 + resolution: "resolve@patch:resolve@npm%3A1.22.10#~builtin::version=1.22.10&hash=c3c19d" + dependencies: + is-core-module: ^2.16.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 8aac1e4e4628bd00bf4b94b23de137dd3fe44097a8d528fd66db74484be929936e20c696e1a3edf4488f37e14180b73df6f600992baea3e089e8674291f16c9d + languageName: node + linkType: hard + "resolve@patch:resolve@^1.22.4#~builtin": version: 1.22.4 resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d" @@ -4695,6 +6384,18 @@ __metadata: languageName: node linkType: hard +"schema-utils@npm:^4.0.0": + version: 4.3.0 + resolution: "schema-utils@npm:4.3.0" + dependencies: + "@types/json-schema": ^7.0.9 + ajv: ^8.9.0 + ajv-formats: ^2.1.1 + ajv-keywords: ^5.1.0 + checksum: 3dbd9056727c871818eaf3cabeeb5c9e173ae2b17bbf2a9c7a2e49c220fa1a580e44df651c876aea3b4926cecf080730a39e28202cb63f2b68d99872b49cd37a + languageName: node + linkType: hard + "secp256k1@npm:^5.0.0": version: 5.0.0 resolution: "secp256k1@npm:5.0.0" @@ -5258,6 +6959,37 @@ __metadata: languageName: node linkType: hard +"unicode-canonical-property-names-ecmascript@npm:^2.0.0": + version: 2.0.1 + resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.1" + checksum: 3c3dabdb1d22aef4904399f9e810d0b71c0b12b3815169d96fac97e56d5642840c6071cf709adcace2252bc6bb80242396c2ec74b37224eb015c5f7aca40bad7 + languageName: node + linkType: hard + +"unicode-match-property-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-match-property-ecmascript@npm:2.0.0" + dependencies: + unicode-canonical-property-names-ecmascript: ^2.0.0 + unicode-property-aliases-ecmascript: ^2.0.0 + checksum: 1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a + languageName: node + linkType: hard + +"unicode-match-property-value-ecmascript@npm:^2.1.0": + version: 2.2.0 + resolution: "unicode-match-property-value-ecmascript@npm:2.2.0" + checksum: 9e3151e1d0bc6be35c4cef105e317c04090364173e8462005b5cde08a1e7c858b6586486cfebac39dc2c6c8c9ee24afb245de6d527604866edfa454fe2a35fae + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^2.0.0": + version: 2.1.0 + resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" + checksum: 243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b + languageName: node + linkType: hard + "unique-filename@npm:^3.0.0": version: 3.0.0 resolution: "unique-filename@npm:3.0.0" @@ -5276,6 +7008,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.1.1": + version: 1.1.2 + resolution: "update-browserslist-db@npm:1.1.2" + dependencies: + escalade: ^3.2.0 + picocolors: ^1.1.1 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 088d2bad8ddeaeccd82d87d3f6d736d5256d697b725ffaa2b601dfd0ec16ba5fad20db8dcdccf55396e1a36194236feb69e3f5cce772e5be15a5e4261ff2815d + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -5295,6 +7041,16 @@ __metadata: languageName: node linkType: hard +"utf-8-validate@npm:^6.0.5": + version: 6.0.5 + resolution: "utf-8-validate@npm:6.0.5" + dependencies: + node-gyp: latest + node-gyp-build: ^4.3.0 + checksum: ab6bd5b0db2241a990a9e1c434a29194900f9f8f715158b56d591306634cdd4f748e91b965d91a32fd459c86b082ec0a35d369bbc4efbb243b48f593c14448e8 + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" @@ -5324,6 +7080,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^9.0.1": + version: 9.0.1 + resolution: "uuid@npm:9.0.1" + bin: + uuid: dist/bin/uuid + checksum: 39931f6da74e307f51c0fb463dc2462807531dc80760a9bff1e35af4316131b4fc3203d16da60ae33f07fdca5b56f3f1dd662da0c99fea9aaeab2004780cc5f4 + languageName: node + linkType: hard + "vlq@npm:^0.2.2": version: 0.2.3 resolution: "vlq@npm:0.2.3" @@ -5524,6 +7289,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -5560,6 +7332,13 @@ __metadata: languageName: node linkType: hard +"yocto-queue@npm:^1.0.0": + version: 1.1.1 + resolution: "yocto-queue@npm:1.1.1" + checksum: f2e05b767ed3141e6372a80af9caa4715d60969227f38b1a4370d60bffe153c9c5b33a862905609afc9b375ec57cd40999810d20e5e10229a204e8bde7ef255c + languageName: node + linkType: hard + "zod@npm:3.21.4": version: 3.21.4 resolution: "zod@npm:3.21.4" diff --git a/packages/playground-next/eslint.config.mjs b/packages/playground-next/eslint.config.mjs index c85fb67c4..61a0b47ac 100644 --- a/packages/playground-next/eslint.config.mjs +++ b/packages/playground-next/eslint.config.mjs @@ -1,6 +1,10 @@ import { dirname } from "path"; import { fileURLToPath } from "url"; import { FlatCompat } from "@eslint/eslintrc"; +import typescript from "@typescript-eslint/eslint-plugin"; +import react from "eslint-plugin-react"; +import prettier from "eslint-plugin-prettier"; +import tsParser from "@typescript-eslint/parser"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -10,7 +14,47 @@ const compat = new FlatCompat({ }); const eslintConfig = [ - ...compat.extends("next/core-web-vitals", "next/typescript"), + ...compat.extends( + "next/core-web-vitals", + "next/typescript", + "plugin:react/recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ), + { + files: ["**/*.ts", "**/*.tsx"], + plugins: { + "@typescript-eslint": typescript, + react: react, + prettier: prettier + }, + languageOptions: { + parser: tsParser, + ecmaVersion: 2021, + sourceType: "module", + parserOptions: { + ecmaFeatures: { + jsx: true + } + } + }, + settings: { + react: { + version: "detect" + } + }, + rules: { + "prettier/prettier": ["error", { + "endOfLine": "auto" + }], + "@typescript-eslint/no-unused-vars": ["error", { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + }], + "react/react-in-jsx-scope": "off", + "@next/next/no-img-element": "warn" + } + } ]; export default eslintConfig; diff --git a/packages/playground-next/next.config.ts b/packages/playground-next/next.config.ts index e9ffa3083..b8b2a9a3a 100644 --- a/packages/playground-next/next.config.ts +++ b/packages/playground-next/next.config.ts @@ -1,7 +1,8 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + reactStrictMode: false, + /* other config options here */ }; export default nextConfig; diff --git a/packages/playground-next/package.json b/packages/playground-next/package.json index 9ec03864a..d1c10f28e 100644 --- a/packages/playground-next/package.json +++ b/packages/playground-next/package.json @@ -10,7 +10,12 @@ "allow-scripts": "echo 'NA'" }, "dependencies": { + "@metamask/api-specs": "^0.10.13", + "@metamask/sdk-multichain": "workspace:^", "@metamask/sdk-react": "workspace:^", + "@metamask/utils": "^11.0.1", + "@open-rpc/meta-schema": "^1.14.9", + "@open-rpc/schema-utils-js": "^2.0.5", "next": "15.1.4", "react": "^19.0.0", "react-dom": "^19.0.0" @@ -22,6 +27,9 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "15.1.4", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.2", + "prettier": "^3.4.2", "typescript": "^5" } } diff --git a/packages/playground-next/src/app/favicon.ico b/packages/playground-next/public/favicon.ico similarity index 100% rename from packages/playground-next/src/app/favicon.ico rename to packages/playground-next/public/favicon.ico diff --git a/packages/playground-next/src/app/globals.css b/packages/playground-next/src/app/globals.css deleted file mode 100644 index e3734be15..000000000 --- a/packages/playground-next/src/app/globals.css +++ /dev/null @@ -1,42 +0,0 @@ -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } -} diff --git a/packages/playground-next/src/app/layout.tsx b/packages/playground-next/src/app/layout.tsx deleted file mode 100644 index 2be6aef14..000000000 --- a/packages/playground-next/src/app/layout.tsx +++ /dev/null @@ -1,41 +0,0 @@ -'use client'; - -import { Geist } from "next/font/google"; -import "./globals.css"; -import { MetaMaskProvider } from "@metamask/sdk-react"; -import { useEffect, useState } from "react"; - -const geist = Geist({ - variable: "--font-geist", - subsets: ["latin"], -}); - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - const [dappUrl, setDappUrl] = useState(""); - - useEffect(() => { - setDappUrl(window.location.href); - }, []); - - return ( - - - - <>{children} - - - - ); -} diff --git a/packages/playground-next/src/app/page.module.css b/packages/playground-next/src/app/page.module.css deleted file mode 100644 index 83ff5a1e2..000000000 --- a/packages/playground-next/src/app/page.module.css +++ /dev/null @@ -1,35 +0,0 @@ -.container { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 100vh; - padding: 20px; - gap: 20px; -} - -.button { - background: var(--foreground); - color: var(--background); - border: none; - padding: 12px 24px; - border-radius: 8px; - font-family: var(--font-geist); - cursor: pointer; - transition: opacity 0.2s; -} - -.button:hover { - opacity: 0.8; -} - -.address { - font-family: var(--font-geist); - background: var(--foreground); - color: var(--background); - padding: 12px 24px; - border-radius: 8px; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; -} diff --git a/packages/playground-next/src/components/DynamicInputs.tsx b/packages/playground-next/src/components/DynamicInputs.tsx new file mode 100644 index 000000000..5cf8b3729 --- /dev/null +++ b/packages/playground-next/src/components/DynamicInputs.tsx @@ -0,0 +1,70 @@ +import React, { useCallback } from 'react'; + +export enum INPUT_LABEL_TYPE { + ADDRESS = 'Address', + SCOPE = 'Scope', +} + +const LABEL_PLACEHOLDER = { + [INPUT_LABEL_TYPE.ADDRESS]: '0x483b...5f97', + [INPUT_LABEL_TYPE.SCOPE]: 'eip155:1', +}; + +type DynamicInputsProps = { + inputArray: string[]; + setInputArray: React.Dispatch>; + label: INPUT_LABEL_TYPE; +}; + +const DynamicInputs: React.FC = ({ + inputArray, + setInputArray, + label, +}) => { + const handleInputChange = useCallback( + (index: number, value: string) => { + const newInputs = [...inputArray]; + newInputs[index] = value; + setInputArray(newInputs); + }, + [inputArray, setInputArray], + ); + + const addInput = useCallback(() => { + if (inputArray.length < 5) { + setInputArray([...inputArray, '']); + } + }, [setInputArray, inputArray]); + + return ( +
+ {inputArray.map((input, index) => ( +
+ + {index === inputArray.length - 1 && inputArray.length < 5 && ( + + )} +
+ ))} +
+ ); +}; + +export default DynamicInputs; diff --git a/packages/playground-next/src/components/WalletList.css b/packages/playground-next/src/components/WalletList.css new file mode 100644 index 000000000..6cf232b60 --- /dev/null +++ b/packages/playground-next/src/components/WalletList.css @@ -0,0 +1,82 @@ +.wallet-list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); + gap: 20px; + padding: 20px; +} + + +.wallet-card { + background-color: #f0f0f0; + border-radius: 10px; + padding: 20px; + display: flex; + flex-direction: column; + align-items: center; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + width: 350px; +} + +.wallet-card button:disabled { + background-color: #4299e1; + opacity: 0.7; + cursor: not-allowed; +} + +.wallet-card button:disabled:hover { + background-color: #4299e1; +} + +.wallet-icon { + width: 50px; + height: 50px; + border-radius: 25px; + margin-right: 15px; +} + +.wallet-info { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + width: 100%; +} + +.wallet-info button { + margin-top: 1rem; +} + +.wallet-name { + margin: 0 0 10px 0; + font-size: 18px; + color: #333; +} + +.wallet-uuid, +.wallet-rdns, +.wallet-extension-id { + margin: 5px 0; + font-size: 14px; + color: #666; +} + +.wallet-card button { + align-self: stretch; + margin-top: 20px; + padding: 10px 15px; + background-color: #4299e1; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s; +} + +.wallet-card button:hover:not(:disabled) { + background-color: #3182ce; +} + +.wallet-card button:disabled { + background-color: #cccccc; + cursor: not-allowed; +} diff --git a/packages/playground-next/src/components/WalletList.tsx b/packages/playground-next/src/components/WalletList.tsx new file mode 100644 index 000000000..5b7f725fe --- /dev/null +++ b/packages/playground-next/src/components/WalletList.tsx @@ -0,0 +1,74 @@ +import type { MouseEventHandler } from 'react'; +import React from 'react'; +import './WalletList.css'; + +export type WalletMapEntry = { + params: { + name: string; + uuid: string; + rdns: string; + icon: string; + extensionId?: string; + }; +}; + +type WalletListProps = { + wallets: Record; + handleClick: (extensionId: string) => Promise; + connectedExtensionId: string; +}; + +function WalletList({ + wallets, + handleClick, + connectedExtensionId, +}: WalletListProps) { + const handleWalletClick = + (extensionId: string): MouseEventHandler => + (ev) => { + ev.preventDefault(); + + handleClick(extensionId); + }; + + if (Object.keys(wallets).length === 0) { + return

No wallets detected

; + } + + return ( +
+ {Object.values(wallets).map((wallet) => { + const isConnected = wallet.params.extensionId === connectedExtensionId; + return ( +
+ {`${wallet.params.name} +
+

{wallet.params.name}

+

UUID: {wallet.params.uuid}

+

RDNS: {wallet.params.rdns}

+ {wallet.params.extensionId && ( + <> +

+ Extension ID: {wallet.params.extensionId} +

+ + + )} +
+
+ ); + })} +
+ ); +} + +export default WalletList; diff --git a/packages/playground-next/src/constants/methods.ts b/packages/playground-next/src/constants/methods.ts new file mode 100644 index 000000000..53f5b1e0d --- /dev/null +++ b/packages/playground-next/src/constants/methods.ts @@ -0,0 +1,167 @@ +// packages/sdk-multichain/src/constants/methods.ts +import MetaMaskOpenRPCDocument from '@metamask/api-specs'; +import { parseCaipAccountId, parseCaipChainId } from '@metamask/utils'; +import type { CaipAccountId, CaipChainId, Json } from '@metamask/utils'; + +/** + * Methods that require an account parameter. + */ +export const METHODS_REQUIRING_PARAM_INJECTION = { + eth_sendTransaction: true, + eth_signTypedData_v4: true, + personal_sign: true, + eth_getBalance: true, +} as const; + +/** + * Injects address and chainId (where applicable) into example params for a given method. + * @param method - The method to inject the address into. + * @param exampleParams - The example params to inject the address into. + * @param addressToInject - The address to inject. + * @param scopeToInject - The scope to inject the address into. + * @returns The updated example params with the address injected. + */ +export const injectParams = ( + method: string, + exampleParams: Json, + addressToInject: CaipAccountId, + scopeToInject: CaipChainId, +): Json => { + const { address: parsedAddress } = parseCaipAccountId(addressToInject); + const { reference: chainId } = parseCaipChainId(scopeToInject); + + if ( + !(method in METHODS_REQUIRING_PARAM_INJECTION) || + typeof exampleParams !== 'object' || + exampleParams === null || + !('method' in exampleParams) || + !('params' in exampleParams) || + !Array.isArray(exampleParams.params) + ) { + return exampleParams; + } + + switch (method) { + case 'eth_sendTransaction': + if ( + exampleParams.params.length > 0 && + typeof exampleParams.params[0] === 'object' && + exampleParams.params[0] !== null + ) { + return { + ...exampleParams, + params: [ + { + ...exampleParams.params[0], + from: parsedAddress, + to: parsedAddress, + value: '0x0', + }, + ...exampleParams.params.slice(1), + ], + }; + } + break; + + case 'personal_sign': + if (exampleParams.params.length >= 2) { + return { + ...exampleParams, + params: [ + exampleParams.params[0], + parsedAddress, + ...exampleParams.params.slice(2), + ] as Json[], + }; + } + break; + + case 'eth_signTypedData_v4': + if ( + exampleParams.params.length >= 2 && + typeof exampleParams.params[1] === 'object' && + exampleParams.params[1] !== null + ) { + const typedData = exampleParams.params[1]; + if ( + typeof typedData === 'object' && + typedData !== null && + 'domain' in typedData && + typeof typedData.domain === 'object' && + typedData.domain !== null + ) { + return { + ...exampleParams, + params: [ + parsedAddress, + { + ...typedData, + domain: { + ...typedData.domain, + chainId, + }, + }, + ], + }; + } + } + break; + + case 'eth_getBalance': + return { + ...exampleParams, + params: [parsedAddress, 'latest'], + }; + + default: + break; + } + + return exampleParams; +}; + +/** + * Known Wallet RPC methods. + */ +export const KnownWalletRpcMethods: string[] = [ + 'wallet_registerOnboarding', + 'wallet_scanQRCode', +]; + +/** + * Wallet methods that are EIP-155 compatible but not scoped to a specific chain. + */ +export const WalletEip155Methods = ['wallet_addEthereumChain']; + +/** + * EIP-155 specific notifications. + */ +export const Eip155Notifications = ['eth_subscription']; + +/** + * Methods that are only available in the EIP-1193 wallet provider. + */ +const Eip1193OnlyMethods = [ + 'wallet_switchEthereumChain', + 'wallet_getPermissions', + 'wallet_requestPermissions', + 'wallet_revokePermissions', + 'eth_requestAccounts', + 'eth_accounts', + 'eth_coinbase', + 'net_version', + 'metamask_logWeb3ShimUsage', + 'metamask_getProviderState', + 'metamask_sendDomainMetadata', + 'wallet_registerOnboarding', +]; + +/** + * All MetaMask methods, except for ones we have specified in the constants above. + */ +export const Eip155Methods = MetaMaskOpenRPCDocument.methods + // eslint-disable-next-line @typescript-eslint/no-shadow + .map(({ name }: { name: string }) => name) + .filter((method: string) => !WalletEip155Methods.includes(method)) + .filter((method: string) => !KnownWalletRpcMethods.includes(method)) + .filter((method: string) => !Eip1193OnlyMethods.includes(method)); diff --git a/packages/playground-next/src/constants/networks.ts b/packages/playground-next/src/constants/networks.ts new file mode 100644 index 000000000..4b2fb2464 --- /dev/null +++ b/packages/playground-next/src/constants/networks.ts @@ -0,0 +1,13 @@ +// packages/sdk-multichain/src/constants/networks.ts +export const FEATURED_NETWORKS = { + 'eip155:1': 'Ethereum Mainnet', + 'eip155:59144': 'Linea Mainnet', + 'eip155:42161': 'Arbitrum One', + 'eip155:43114': 'Avalanche Network C-Chain', + 'eip155:56': 'BNB Chain', + 'eip155:10': 'OP Mainnet', + 'eip155:137': 'Polygon Mainnet', + 'eip155:324': 'zkSync Era Mainnet', + 'eip155:8453': 'Base Mainnet', + 'eip155:1337': 'Localhost', +} as const; diff --git a/packages/playground-next/src/helpers/JsonHelpers.ts b/packages/playground-next/src/helpers/JsonHelpers.ts new file mode 100644 index 000000000..c6db0d8b2 --- /dev/null +++ b/packages/playground-next/src/helpers/JsonHelpers.ts @@ -0,0 +1,60 @@ +// packages/sdk-multichain/src/utils/JsonHelpers.ts +import type { + ContentDescriptorObject, + ExampleObject, + ExamplePairingObject, + MethodObject, +} from '@open-rpc/meta-schema'; +import type { Json } from '@metamask/utils'; + +const paramsToObj = ( + params: Record[], + methodParams: ContentDescriptorObject[], +): Record => { + return params.reduce((acc, val, i) => { + const paramName = methodParams[i]?.name; + if (paramName) { + acc[paramName] = val; + } + return acc; + }, {}); +}; + +export const openRPCExampleToJSON = (method: MethodObject) => { + if (!method.examples || method.examples.length === 0) { + return { + method: method.name, + params: [], + }; + } + const examplePairing = method.examples?.[0]; + const ex = examplePairing as ExamplePairingObject; + const paramsFromExample = ex.params.map( + (example) => (example as ExampleObject).value, + ); + const params = + method.paramStructure === 'by-name' + ? paramsToObj( + paramsFromExample, + method.params as ContentDescriptorObject[], + ) + : paramsFromExample; + return { + method: method.name, + params, + } as Json; +}; + +export const truncateJSON = ( + json: Json, + maxLength = 100, +): { text: string; truncated: boolean } => { + const stringified = JSON.stringify(json).slice(0, maxLength); + if (stringified.length <= maxLength) { + return { text: stringified, truncated: false }; + } + return { + text: stringified.slice(0, maxLength), + truncated: true, + }; +}; diff --git a/packages/playground-next/src/hooks/useConnection.ts b/packages/playground-next/src/hooks/useConnection.ts new file mode 100644 index 000000000..5604c0c17 --- /dev/null +++ b/packages/playground-next/src/hooks/useConnection.ts @@ -0,0 +1,33 @@ +import { useState, useCallback } from 'react'; + +interface UseConnectionReturn { + connectionError: string | null; + handleConnect: () => Promise; + setConnectionError: (error: string | null) => void; +} + +export function useConnection( + connect: (params: { extensionId: string }) => Promise, +): UseConnectionReturn { + const [connectionError, setConnectionError] = useState(null); + + const handleConnect = useCallback(async () => { + try { + setConnectionError(null); + await connect({ extensionId: 'nfdjnfhlblppdgdplngdjgpifllaamoc' }); + } catch (error) { + const errorMessage = + error instanceof Error + ? error.message + : 'Failed to connect to MetaMask'; + setConnectionError(errorMessage); + console.error('Connection error:', error); + } + }, [connect]); + + return { + connectionError, + handleConnect, + setConnectionError, + }; +} diff --git a/packages/playground-next/src/hooks/useMultichain.ts b/packages/playground-next/src/hooks/useMultichain.ts new file mode 100644 index 000000000..c0af6fba7 --- /dev/null +++ b/packages/playground-next/src/hooks/useMultichain.ts @@ -0,0 +1,349 @@ +import { eip6963RequestProvider } from '@metamask/sdk'; +import { + CreateSessionParams, + getStoredSession, + MetamaskMultichain, + MultichainEvents, + performMultichainInit, + SessionData, + SessionEventData, +} from '@metamask/sdk-multichain'; +import { CaipChainId, Json } from '@metamask/utils'; +import { useCallback, useEffect, useRef, useState } from 'react'; + +interface UseMultichainParams { + onSessionChanged?: (event: SessionEventData) => void; + onNotification?: (notification: unknown) => void; + defaultExtensionId?: string; + useExistingProvider?: boolean; +} + +interface UseMultichainReturn { + isConnected: boolean; + currentSession: SessionData | null; + extensionId: string; + error: string | null; + isInitializing: boolean; + connect: (params: { extensionId: string }) => Promise; + disconnect: () => void; + createSession: (params: CreateSessionParams) => Promise; + getSession: (params?: { sessionId?: string }) => Promise; + revokeSession: (params?: { sessionId?: string }) => Promise; + invokeMethod: (params: { + scope: CaipChainId; + request: { method: string; params: Json[] }; + }) => Promise; + addListener: ( + event: K, + listener: MultichainEvents[K], + ) => void; + removeListener: ( + event: K, + listener: MultichainEvents[K], + ) => void; +} + +// React hook implementation +export const useMultichain = ({ + onSessionChanged, + onNotification, + defaultExtensionId = 'nfdjnfhlblppdgdplngdjgpifllaamoc', + useExistingProvider = false, +}: UseMultichainParams = {}): UseMultichainReturn => { + const [multichain, setMultichain] = useState(null); + const [isConnected, setIsConnected] = useState(false); + const [currentSession, setCurrentSession] = useState( + null, + ); + const [extensionId, setExtensionId] = useState( + defaultExtensionId ?? '', + ); + const [error, setError] = useState(null); + const [isInitializing, setIsInitializing] = useState(true); + + const multichainInitRef = useRef(false); + const prevProviderTypeRef = useRef(useExistingProvider); + + const init = useCallback(async () => { + try { + console.debug('[useMultichain] Starting initialization', { + defaultExtensionId, + useExistingProvider, + storedSession: localStorage.getItem('metamask_multichain_session'), + }); + + let existingProvider; + if (useExistingProvider) { + try { + existingProvider = await eip6963RequestProvider({ + rdns: 'io.metamask.flask', + }); + console.debug( + '[useMultichain] Found existing provider:', + existingProvider, + ); + } catch (err) { + console.warn('[useMultichain] Failed to get existing provider:', err); + } + } + + const instance = await performMultichainInit({ + extensionId: defaultExtensionId, + onSessionChanged, + onNotification, + storageKey: 'metamask_multichain_session', + providerConfig: existingProvider + ? { + existingProvider, + } + : undefined, + }); + + console.log(`[useMultichain] Multichain instance`, instance); + + setMultichain(instance); + + // Only try to get session if we have a stored session + const storedSession = getStoredSession('metamask_multichain_session'); + if (storedSession) { + try { + // First try to connect using stored extension ID + const connected = await instance.connect({ + extensionId: storedSession.extensionId, + }); + + if (connected) { + const session = await instance.getSession(); + if (session) { + setIsConnected(true); + setCurrentSession(session); + setExtensionId(storedSession.extensionId); + } else { + throw new Error('No valid session found'); + } + } else { + throw new Error('Failed to connect to stored extension'); + } + } catch (sessionError) { + console.debug( + '[useMultichain] Failed to restore session:', + sessionError, + ); + // Clear stored session if it's invalid + localStorage.removeItem('metamask_multichain_session'); + setIsConnected(false); + setCurrentSession(null); + // Don't set error here as this is an expected case + } + } + + setError(null); + } catch (error) { + console.error('[useMultichain] Initialization failed:', error); + setError(error instanceof Error ? error.message : 'Failed to initialize'); + setIsConnected(false); + setCurrentSession(null); + } finally { + setIsInitializing(false); + } + }, [ + defaultExtensionId, + onSessionChanged, + onNotification, + useExistingProvider, + ]); + + // Initialize multichain instance + useEffect(() => { + // Allow first init or reinitialize if provider type changed + if ( + multichainInitRef.current && + prevProviderTypeRef.current === useExistingProvider + ) { + return; + } + + console.debug('[useMultichain] Starting initialization', { + defaultExtensionId, + useExistingProvider, + storedSession: localStorage.getItem('metamask_multichain_session'), + }); + + prevProviderTypeRef.current = useExistingProvider; + multichainInitRef.current = true; + + init(); + + return () => { + console.debug('[useMultichain] Cleanup - disconnecting'); + multichain?.disconnect(); + }; + }, [ + defaultExtensionId, + onSessionChanged, + onNotification, + init, + useExistingProvider, + multichain, + ]); + + const connect = useCallback( + async (params?: { extensionId: string }) => { + if (!multichain) { + throw new Error('Multichain not initialized. Please try again.'); + } + + try { + setError(null); + const { extensionId: connExtensionId } = params ?? { + extensionId: defaultExtensionId, + }; + console.debug('[useMultichain] Connecting', { + extensionId: connExtensionId, + }); + + const connected = await multichain.connect({ + extensionId: connExtensionId, + }); + + if (!connected) { + throw new Error( + 'Failed to connect to MetaMask. Please make sure it is installed and unlocked.', + ); + } + + console.debug('[useMultichain] Connection result', { connected }); + setIsConnected(connected); + setExtensionId(connExtensionId); + + // Try to get or create session after successful connection + try { + const session = await multichain.getSession(); + if (session) { + setCurrentSession(session); + } + } catch (sessionError) { + console.debug( + '[useMultichain] No existing session found after connect', + sessionError, + ); + // This is normal for first-time connections, don't throw + } + + return connected; + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : 'Failed to connect'; + console.error('[useMultichain] Connection error:', errorMessage); + setIsConnected(false); + setError(errorMessage); + throw error; + } + }, + [multichain, defaultExtensionId], + ); + + const getSession = useCallback( + async (params?: { sessionId?: string }) => { + if (!multichain) { + throw new Error('Multichain not initialized'); + } + if (!isConnected) { + throw new Error('Provider not connected. Please connect first.'); + } + return multichain.getSession(params); + }, + [multichain, isConnected], + ); + + const disconnect = useCallback(() => { + if (!multichain) { + console.debug( + '[useMultichain] Disconnect called but multichain not initialized', + ); + return; + } + console.debug('[useMultichain] Disconnecting'); + multichain.disconnect(); + setIsConnected(false); + setCurrentSession(null); + setExtensionId(''); + }, [multichain]); + + const createSession = useCallback( + async (params: CreateSessionParams) => { + if (!multichain) throw new Error('Multichain not initialized'); + console.debug('[useMultichain] Creating new session', { params }); + const session = await multichain.createSession(params); + console.debug('[useMultichain] Session created', { + sessionId: session.sessionId, + storedSession: localStorage.getItem('metamask_multichain_session'), + }); + setCurrentSession(session); + setIsConnected(true); + return session; + }, + [multichain], + ); + + const revokeSession = useCallback( + async (params?: { sessionId?: string }) => { + if (!multichain) throw new Error('Multichain not initialized'); + const result = await multichain.revokeSession(params); + if (result) { + setCurrentSession(null); + } + return result; + }, + [multichain], + ); + + const invokeMethod = useCallback( + async (params: { + scope: CaipChainId; + request: { method: string; params: Json[] }; + }) => { + if (!multichain) throw new Error('Multichain not initialized'); + return multichain.invokeMethod(params); + }, + [multichain], + ); + + const addListener = useCallback( + ( + event: K, + listener: MultichainEvents[K], + ) => { + if (!multichain) throw new Error('Multichain not initialized'); + multichain.addListener(event, listener); + }, + [multichain], + ); + + const removeListener = useCallback( + ( + event: K, + listener: MultichainEvents[K], + ) => { + if (!multichain) throw new Error('Multichain not initialized'); + multichain.removeListener(event, listener); + }, + [multichain], + ); + + return { + isConnected, + currentSession, + extensionId, + error, + isInitializing, + connect, + disconnect, + createSession, + getSession, + revokeSession, + invokeMethod, + addListener, + removeListener, + }; +}; diff --git a/packages/playground-next/src/multichain-types.ts b/packages/playground-next/src/multichain-types.ts new file mode 100644 index 000000000..571dff82e --- /dev/null +++ b/packages/playground-next/src/multichain-types.ts @@ -0,0 +1,40 @@ +import { SessionData } from '@metamask/sdk-multichain'; +import { CaipChainId, Json } from '@metamask/utils'; +import { FEATURED_NETWORKS } from './constants/networks'; + +export type NetworkId = keyof typeof FEATURED_NETWORKS; + +export interface WalletHistoryEntry { + timestamp: number; + data: unknown; +} + +export interface SessionMethodResult { + timestamp: number; + method: string; + data: SessionData | null | boolean; +} + +export interface InvokeMethodResult { + result: Json; + request: Json; +} + +export interface InvokeMethodRequest { + method: string; + params: { + scope: CaipChainId; + request: { + method: string; + params: Json[]; + }; + }; +} + +export interface ScopeMethodResults { + [method: string]: InvokeMethodResult[]; +} + +export interface InvokeMethodResults { + [scope: string]: ScopeMethodResults; +} diff --git a/packages/playground-next/src/pages/_app.tsx b/packages/playground-next/src/pages/_app.tsx new file mode 100644 index 000000000..850893693 --- /dev/null +++ b/packages/playground-next/src/pages/_app.tsx @@ -0,0 +1,8 @@ +import '../styles/globals.css'; // Import global CSS here +import type { AppProps } from 'next/app'; + +function MyApp({ Component, pageProps }: AppProps) { + return ; +} + +export default MyApp; diff --git a/packages/playground-next/src/pages/index.tsx b/packages/playground-next/src/pages/index.tsx new file mode 100644 index 000000000..4254f0a93 --- /dev/null +++ b/packages/playground-next/src/pages/index.tsx @@ -0,0 +1,837 @@ +'use client'; + +import { MetaMaskOpenRPCDocument } from '@metamask/api-specs'; +import { SessionData, SessionEventData } from '@metamask/sdk-multichain'; +import { + CaipAccountId, + CaipChainId, + Json, + parseCaipAccountId, +} from '@metamask/utils'; +import { MethodObject, OpenrpcDocument } from '@open-rpc/meta-schema'; +import { parseOpenRPCDocument } from '@open-rpc/schema-utils-js'; +import { useCallback, useEffect, useState } from 'react'; +import DynamicInputs, { INPUT_LABEL_TYPE } from '../components/DynamicInputs'; +import { useMultichain } from '../hooks/useMultichain'; + +import { + injectParams, + METHODS_REQUIRING_PARAM_INJECTION, +} from '../constants/methods'; +import { FEATURED_NETWORKS } from '../constants/networks'; +import { openRPCExampleToJSON, truncateJSON } from '../helpers/JsonHelpers'; +import { useConnection } from '../hooks/useConnection'; +import { + InvokeMethodRequest, + InvokeMethodResults, + NetworkId, + SessionMethodResult, + WalletHistoryEntry, +} from '../multichain-types'; +import styles from '../styles/page.module.css'; + +// Simplify enum for provider types +export enum ProviderType { + CHROME_EXTENSION = 'chrome_extension', + EXISTING_PROVIDER = 'existing_provider', +} + +const defaultSessionsScopes: Record = { + 'eip155:1': false, + 'eip155:59144': false, + 'eip155:42161': false, + 'eip155:43114': false, + 'eip155:56': false, + 'eip155:10': false, + 'eip155:137': false, + 'eip155:324': false, + 'eip155:8453': false, + 'eip155:1337': false, +}; + +export default function Page() { + // State declarations with proper types + const [addresses, setAddresses] = useState([]); + const [metamaskOpenrpcDocument, setMetamaskOpenrpcDocument] = + useState(); + const [sessionsScopes, setSessionsScopes] = useState< + Record + >(defaultSessionsScopes); + const [selectedAccounts, setSelectedAccounts] = useState< + Record + >({}); + const [selectedMethods, setSelectedMethods] = useState< + Record + >({}); + // Custom chain IDs that can be added beyond the default networks + const [customScopes, setCustomScopes] = useState(['']); + const [invokeMethodRequests, setInvokeMethodRequests] = useState< + Record + >({}); + const [invokeMethodResults, setInvokeMethodResults] = + useState({}); + const [sessionMethodHistory, setSessionMethodHistory] = useState< + SessionMethodResult[] + >([]); + const [walletSessionChangedHistory, setWalletSessionChangedHistory] = + useState([]); + const [walletNotifyHistory, setWalletNotifyHistory] = useState< + WalletHistoryEntry[] + >([]); + const [selectedProviderType, setSelectedProviderType] = + useState(ProviderType.CHROME_EXTENSION); + + const setInitialMethodsAndAccounts = useCallback( + (session: SessionData) => { + const initialSelectedMethods: Record = {}; + const initialSelectedAccounts: Record = {}; + + Object.entries(session.sessionScopes || {}).forEach( + ([scope, details]) => { + if (details.accounts?.[0]) { + initialSelectedAccounts[scope] = details.accounts[0]; + } + initialSelectedMethods[scope] = 'eth_blockNumber'; + + const example = metamaskOpenrpcDocument?.methods.find( + (method) => (method as MethodObject).name === 'eth_blockNumber', + ); + + if (example) { + const defaultRequest = { + method: 'wallet_invokeMethod', + params: { + scope, + request: openRPCExampleToJSON(example as MethodObject), + }, + }; + + setInvokeMethodRequests((prev) => ({ + ...prev, + [scope]: JSON.stringify(defaultRequest, null, 2), + })); + } + }, + ); + + setSelectedMethods(initialSelectedMethods); + setSelectedAccounts(initialSelectedAccounts); + }, + [metamaskOpenrpcDocument], + ); + + const handleSessionChangedNotification = useCallback( + (event: SessionEventData) => { + setWalletSessionChangedHistory((prev) => { + const timestamp = Date.now(); + if (prev.some((entry) => entry.timestamp === timestamp)) { + return prev; + } + return [{ timestamp, data: event }, ...prev]; + }); + + if (event.session?.sessionScopes) { + // Convert session scopes to boolean record + const newScopes = Object.keys(event.session.sessionScopes).reduce< + Record + >( + (acc, scope) => ({ + ...acc, + [scope as NetworkId]: true, + }), + { ...defaultSessionsScopes }, + ); + setSessionsScopes(newScopes); + setInitialMethodsAndAccounts(event.session); + } + }, + [setInitialMethodsAndAccounts], + ); + + const handleNotification = useCallback((notification: unknown) => { + console.log('receive wallet notification', notification); + setWalletNotifyHistory((prev) => { + const timestamp = Date.now(); + if (prev.some((entry) => entry.timestamp === timestamp)) { + return prev; + } + return [{ timestamp, data: notification }, ...prev]; + }); + }, []); + + const { + isConnected, + currentSession, + connect, + disconnect, + createSession, + getSession, + revokeSession, + invokeMethod, + error: multichainError, + isInitializing, + } = useMultichain({ + onSessionChanged: handleSessionChangedNotification, + onNotification: handleNotification, + useExistingProvider: + selectedProviderType === ProviderType.EXISTING_PROVIDER, + }); + + // Initialize connection management + const { connectionError, handleConnect } = useConnection(connect); + + // Initialize OpenRPC document + useEffect(() => { + parseOpenRPCDocument(MetaMaskOpenRPCDocument as OpenrpcDocument) + .then(setMetamaskOpenrpcDocument) + .catch(() => console.error('Error parsing metamask openrpc document')); + }, []); + + const handleCreateSession = async () => { + const selectedChainsArray = Object.entries(sessionsScopes) + .filter(([_, isSelected]) => isSelected) + .map(([chainId]) => chainId as NetworkId); + + try { + const result = await createSession({ + optionalScopes: selectedChainsArray.reduce( + (acc, _chainId) => ({ + ...acc, + }), + {}, + ), + }); + + setSessionMethodHistory((prev) => [ + { + timestamp: Date.now(), + method: 'wallet_createSession', + data: result, + }, + ...prev, + ]); + } catch (error) { + console.error('Error creating session:', error); + } + }; + + const handleGetSession = async () => { + try { + const result = await getSession(); + setSessionMethodHistory((prev) => [ + { + timestamp: Date.now(), + method: 'wallet_getSession', + data: result, + }, + ...prev, + ]); + } catch (error) { + console.error('Error getting session:', error); + } + }; + + const handleRevokeSession = async () => { + try { + const result = await revokeSession(); + setSessionMethodHistory((prev) => [ + { timestamp: Date.now(), method: 'wallet_revokeSession', data: result }, + ...prev, + ]); + } catch (error) { + console.error('Error revoking session:', error); + } + }; + + const handleMethodSelect = useCallback( + (evt: React.ChangeEvent, scope: CaipChainId) => { + const selectedMethod = evt.target.value; + setSelectedMethods((prev) => ({ + ...prev, + [scope]: selectedMethod, + })); + + const example = metamaskOpenrpcDocument?.methods.find( + (method) => (method as MethodObject).name === selectedMethod, + ); + + console.log(`handleMethodSelect: ${selectedMethod}`, example); + console.log(`selectedAccounts: `, selectedAccounts); + + if (example) { + let exampleParams = openRPCExampleToJSON(example as MethodObject); + const selectedAddress = selectedAccounts[scope]; + + console.log(`selectedAddress: ${selectedAddress}`); + + if ( + selectedAddress && + selectedMethod in METHODS_REQUIRING_PARAM_INJECTION + ) { + exampleParams = injectParams( + selectedMethod, + exampleParams, + selectedAddress, + scope, + ); + } + + console.log(`exampleParams: `, exampleParams); + + const defaultRequest: InvokeMethodRequest = { + method: 'wallet_invokeMethod', + params: { + scope, + request: exampleParams as { + method: string; + params: Json[]; + }, + }, + }; + + console.log(`defaultRequest: `, defaultRequest); + + setInvokeMethodRequests((prev) => ({ + ...prev, + [scope]: JSON.stringify(defaultRequest, null, 2), + })); + } + }, + [metamaskOpenrpcDocument, selectedAccounts], + ); + + const handleInvokeMethod = useCallback( + async (scope: CaipChainId, method: string) => { + try { + const requestString = invokeMethodRequests[scope]; + if (!requestString) return; + + const requestObject = JSON.parse(requestString) as InvokeMethodRequest; + const result = await invokeMethod({ + scope, + request: { + method, + params: requestObject.params.request.params, + }, + }); + + setInvokeMethodResults((prev) => ({ + ...prev, + [scope]: { + ...(prev[scope] ?? {}), + [method]: [ + ...(prev[scope]?.[method] ?? []), + { + result: result as Json, + request: requestObject.params.request, + }, + ], + }, + })); + } catch (error) { + // console.error('Error invoking method:', error); + console.warn(`Error invoking method: `, error); + } + }, + [invokeMethod, invokeMethodRequests], + ); + + const handleInvokeAllMethods = useCallback(async () => { + console.debug('[Wallet] Invoking all methods'); + const scopesWithMethods = Object.entries(selectedMethods) + .filter(([_, method]) => method) + .map(([scope, method]) => ({ scope, method })); + + await Promise.all( + scopesWithMethods.map(({ scope, method }) => + handleInvokeMethod(scope as CaipChainId, method), + ), + ); + }, [selectedMethods, handleInvokeMethod]); + + const handleClearInvokeResults = () => { + setInvokeMethodResults({}); + }; + + const handleDisconnect = useCallback(() => { + // First revoke the session if it exists + if (currentSession) { + revokeSession().catch(console.error); + } + + disconnect(); + + // Reset all state to initial values + setAddresses([]); + setSessionsScopes(defaultSessionsScopes); + setSelectedAccounts({}); + setSelectedMethods({}); + setCustomScopes(['']); + setInvokeMethodRequests({}); + setInvokeMethodResults({}); + setSessionMethodHistory([]); + setWalletSessionChangedHistory([]); + setWalletNotifyHistory([]); + }, [currentSession, revokeSession, disconnect]); + + if (isInitializing) { + return ( +
+

MetaMask MultiChain API Test Dapp

+
Initializing...
+
+ ); + } + + return ( +
+

MetaMask MultiChain API Test Dapp

+ + {!isConnected && ( +
+
+

Connection Method

+
+ + +
+
+ + {(connectionError || multichainError) && ( +
+ {connectionError || multichainError} +
+ )} +
+ )} + + {isConnected && !currentSession && ( +
+
+ Connected to MetaMask. Please create a session to continue. +
+
+ )} + + {isConnected && ( +
+ +
+ )} + +
+

Session Lifecycle

+
+
+
+

Create Session

+ {Object.entries(FEATURED_NETWORKS).map( + ([chainId, networkName]) => ( + + ), + )} + + + + 0 ? addresses : ['']} + setInputArray={setAddresses} + label={INPUT_LABEL_TYPE.ADDRESS} + /> + +
+ + + +
+
+ + {currentSession && ( +
+

Connected Accounts

+
    + {Object.values(currentSession.sessionScopes || {}) + .flatMap((scope) => scope.accounts ?? []) + .map((account) => parseCaipAccountId(account).address) + .filter(Boolean) + .filter( + (address, index, array) => + array.indexOf(address) === index, + ) + .map((address) => ( +
  • {address}
  • + ))} +
+ +

Connected Chains

+
    + {Object.keys(currentSession.sessionScopes || {}).map( + (chain) => ( +
  • {chain}
  • + ), + )} +
+
+ )} +
+
+ {/* Session Results */} +
+

Session Lifecycle method results

+
+ {sessionMethodHistory.length > 0 ? ( + sessionMethodHistory.map( + ({ timestamp, method, data }, index) => ( +
+ + + {new Date(timestamp).toLocaleString()} + + {method} + {truncateJSON(data as Json).text} + + +
+                            {JSON.stringify(data, null, 2)}
+                          
+
+
+ ), + ) + ) : ( +

No session method calls

+ )} +
+
+ + {/* Session Changes */} +
+

+ wallet_sessionChanged{' '} +

+
+ {walletSessionChangedHistory.length > 0 ? ( + walletSessionChangedHistory.map( + ({ timestamp, data }, index) => ( +
+ + + {new Date(timestamp).toLocaleString()} + + {truncateJSON(data as Json).text} + + +
+                            {JSON.stringify(data, null, 2)}
+                          
+
+
+ ), + ) + ) : ( +

No session changes detected

+ )} +
+
+
+
+
+
+ + {/* Method invocation section */} + {currentSession?.sessionScopes && isConnected && ( +
+
+
+

Connected Scopes

+ +
+ +
+ {Object.entries(currentSession.sessionScopes).map( + ([scope, details]) => ( +
+

+ {FEATURED_NETWORKS[ + scope as keyof typeof FEATURED_NETWORKS + ] + ? `${ + FEATURED_NETWORKS[ + scope as keyof typeof FEATURED_NETWORKS + ] + } (${scope})` + : scope} +

+ + + + + +
+ Invoke Method Request +
+