@novastera-oss/nitro-metamask 0.6.3 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NitroMetamask.podspec +12 -3
- package/README.md +3 -1
- package/android/build.gradle +14 -32
- package/android/cargo-ecies.gradle +60 -88
- package/android/src/main/aidl/io/metamask/nativesdk/IMessegeService.aidl +8 -0
- package/android/src/main/aidl/io/metamask/nativesdk/IMessegeServiceCallback.aidl +8 -0
- package/android/src/main/java/com/margelo/nitro/nitrometamask/HybridNitroMetamask.kt +101 -3
- package/android/src/main/java/io/metamask/androidsdk/AnyRequest.kt +8 -0
- package/android/src/main/java/io/metamask/androidsdk/ClientMessageServiceCallback.kt +12 -0
- package/android/src/main/java/io/metamask/androidsdk/ClientServiceConnection.kt +42 -0
- package/android/src/main/java/io/metamask/androidsdk/CommunicationClient.kt +525 -0
- package/android/src/main/java/io/metamask/androidsdk/CommunicationClientModule.kt +47 -0
- package/android/src/main/java/io/metamask/androidsdk/CommunicationClientModuleInterface.kt +11 -0
- package/android/src/main/java/io/metamask/androidsdk/Constants.kt +5 -0
- package/android/src/main/java/io/metamask/androidsdk/Crypto.kt +35 -0
- package/android/src/main/java/io/metamask/androidsdk/DappMetadata.kt +36 -0
- package/android/src/main/java/io/metamask/androidsdk/Encryption.kt +9 -0
- package/android/src/main/java/io/metamask/androidsdk/ErrorType.kt +41 -0
- package/android/src/main/java/io/metamask/androidsdk/Ethereum.kt +328 -0
- package/android/src/main/java/io/metamask/androidsdk/EthereumEventCallback.kt +6 -0
- package/android/src/main/java/io/metamask/androidsdk/EthereumMethod.kt +80 -0
- package/android/src/main/java/io/metamask/androidsdk/EthereumRequest.kt +7 -0
- package/android/src/main/java/io/metamask/androidsdk/EthereumState.kt +7 -0
- package/android/src/main/java/io/metamask/androidsdk/KeyExchange.kt +77 -0
- package/android/src/main/java/io/metamask/androidsdk/KeyExchangeMessageType.kt +20 -0
- package/android/src/main/java/io/metamask/androidsdk/KeyStorage.kt +122 -0
- package/android/src/main/java/io/metamask/androidsdk/Logger.kt +18 -0
- package/android/src/main/java/io/metamask/androidsdk/Message.kt +3 -0
- package/android/src/main/java/io/metamask/androidsdk/MessageType.kt +11 -0
- package/android/src/main/java/io/metamask/androidsdk/OriginatorInfo.kt +12 -0
- package/android/src/main/java/io/metamask/androidsdk/RequestError.kt +8 -0
- package/android/src/main/java/io/metamask/androidsdk/RequestInfo.kt +9 -0
- package/android/src/main/java/io/metamask/androidsdk/Result.kt +11 -0
- package/android/src/main/java/io/metamask/androidsdk/RpcRequest.kt +7 -0
- package/android/src/main/java/io/metamask/androidsdk/SDKInfo.kt +6 -0
- package/android/src/main/java/io/metamask/androidsdk/SDKOptions.kt +6 -0
- package/android/src/main/java/io/metamask/androidsdk/SecureStorage.kt +9 -0
- package/android/src/main/java/io/metamask/androidsdk/SessionConfig.kt +10 -0
- package/android/src/main/java/io/metamask/androidsdk/SessionManager.kt +92 -0
- package/android/src/main/java/io/metamask/androidsdk/SubmittedRequest.kt +8 -0
- package/android/src/main/java/io/metamask/androidsdk/TimeStampGenerator.kt +7 -0
- package/android/src/main/jniLibs/arm64-v8a/libecies.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libecies.so +0 -0
- package/android/src/main/jniLibs/x86/libecies.so +0 -0
- package/android/src/main/jniLibs/x86_64/libecies.so +0 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/CancellationStateMachineTest.kt +128 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/ChainIdParsingTest.kt +65 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/ConfigureStateMachineTest.kt +140 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/ConnectSignJsonTest.kt +76 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/MetaMaskInstallationCheckTest.kt +42 -0
- package/android/src/test/java/com/margelo/nitro/nitrometamask/PersonalSignParamsTest.kt +75 -0
- package/ios/Frameworks/Ecies.xcframework/Info.plist +47 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64/Headers/ecies.h +20 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64/Headers/module.modulemap +4 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64/libecies.a +0 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64-simulator/Headers/ecies.h +20 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64-simulator/Headers/module.modulemap +4 -0
- package/ios/Frameworks/Ecies.xcframework/ios-arm64-simulator/libecies.a +0 -0
- package/ios/HybridNitroMetamask.swift +119 -54
- package/ios/NitroMetamaskTests/CancellationStateMachineTests.swift +150 -0
- package/ios/NitroMetamaskTests/ChainIdParsingTests.swift +117 -0
- package/ios/NitroMetamaskTests/ConfigureStateMachineTests.swift +174 -0
- package/ios/NitroMetamaskTests/ConnectSignJsonTests.swift +168 -0
- package/ios/NitroMetamaskTests/DefaultDappUrlTests.swift +80 -0
- package/ios/NitroMetamaskTests/PersonalSignParamsTests.swift +101 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/CommClient.swift +43 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/CommClientFactory.swift +17 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/CommLayer.swift +36 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/DeeplinkCommLayer/Deeplink.swift +26 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/DeeplinkCommLayer/DeeplinkClient.swift +199 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/DeeplinkCommLayer/DeeplinkManager.swift +83 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/DeeplinkCommLayer/String.swift +48 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/DeeplinkCommLayer/URLOpener.swift +19 -0
- package/ios/metamask-ios-sdk/CommunicationLayer/SocketClient.swift +27 -0
- package/ios/metamask-ios-sdk/Crypto/Crypto.swift +72 -0
- package/ios/metamask-ios-sdk/Crypto/Encoding.swift +15 -0
- package/ios/metamask-ios-sdk/Crypto/KeyExchange.swift +236 -0
- package/ios/metamask-ios-sdk/DeviceInfo/DeviceInfo.swift +11 -0
- package/ios/metamask-ios-sdk/Ethereum/AppMetadata.swift +28 -0
- package/ios/metamask-ios-sdk/Ethereum/ErrorType.swift +62 -0
- package/ios/metamask-ios-sdk/Ethereum/Ethereum.swift +810 -0
- package/ios/metamask-ios-sdk/Ethereum/EthereumMethod.swift +111 -0
- package/ios/metamask-ios-sdk/Ethereum/EthereumRequest.swift +40 -0
- package/ios/metamask-ios-sdk/Ethereum/EthereumWrapper.swift +10 -0
- package/ios/metamask-ios-sdk/Ethereum/RPCRequest.swift +14 -0
- package/ios/metamask-ios-sdk/Ethereum/RequestError.swift +88 -0
- package/ios/metamask-ios-sdk/Ethereum/ResponseMethod.swift +22 -0
- package/ios/metamask-ios-sdk/Ethereum/SubmitRequest.swift +26 -0
- package/ios/metamask-ios-sdk/Ethereum/TimestampGenerator.swift +16 -0
- package/ios/metamask-ios-sdk/Extensions/NSRecursiveLock.swift +14 -0
- package/ios/metamask-ios-sdk/Extensions/Notification.swift +10 -0
- package/ios/metamask-ios-sdk/Logger/Logging.swift +27 -0
- package/ios/metamask-ios-sdk/Models/AddChainParameters.swift +35 -0
- package/ios/metamask-ios-sdk/Models/Event.swift +19 -0
- package/ios/metamask-ios-sdk/Models/Mappable.swift +40 -0
- package/ios/metamask-ios-sdk/Models/NativeCurrency.swift +25 -0
- package/ios/metamask-ios-sdk/Models/OriginatorInfo.swift +26 -0
- package/ios/metamask-ios-sdk/Models/RequestInfo.swift +18 -0
- package/ios/metamask-ios-sdk/Models/SignContract.swift +48 -0
- package/ios/metamask-ios-sdk/Models/Typealiases.swift +9 -0
- package/ios/metamask-ios-sdk/Persistence/SecureStore.swift +134 -0
- package/ios/metamask-ios-sdk/Persistence/SessionConfig.swift +24 -0
- package/ios/metamask-ios-sdk/Persistence/SessionManager.swift +56 -0
- package/ios/metamask-ios-sdk/SDK/Dependencies.swift +35 -0
- package/ios/metamask-ios-sdk/SDK/MetaMaskSDK.swift +215 -0
- package/ios/metamask-ios-sdk/SDK/SDKInfo.swift +37 -0
- package/ios/metamask-ios-sdk/SDK/SDKOptions.swift +16 -0
- package/lib/commonjs/index.js +50 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +49 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/__tests__/parseNitroError.test.d.ts +2 -0
- package/lib/typescript/src/__tests__/parseNitroError.test.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +43 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/nitro-metamask.nitro.d.ts +29 -1
- package/lib/typescript/src/specs/nitro-metamask.nitro.d.ts.map +1 -1
- package/package.json +21 -12
- package/react-native.config.js +5 -0
- package/rust/ecies-jni/Cargo.lock +50 -86
- package/rust/ecies-jni/Cargo.toml +1 -1
- package/rust/ecies-jni/src/lib.rs +164 -100
- package/src/__tests__/parseNitroError.test.ts +35 -0
- package/src/index.ts +53 -5
- package/src/specs/nitro-metamask.nitro.ts +29 -1
- package/scripts/verify-16k-page-alignment.py +0 -117
- package/scripts/verify-16k-page-alignment.sh +0 -5
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SecureStore.swift
|
|
3
|
+
// metamask-ios-sdk
|
|
4
|
+
//
|
|
5
|
+
import Foundation
|
|
6
|
+
|
|
7
|
+
public protocol SecureStore {
|
|
8
|
+
func string(for key: String) -> String?
|
|
9
|
+
|
|
10
|
+
func data(for key: String) -> Data?
|
|
11
|
+
|
|
12
|
+
@discardableResult
|
|
13
|
+
func deleteData(for key: String) -> Bool
|
|
14
|
+
|
|
15
|
+
@discardableResult
|
|
16
|
+
func deleteAll() -> Bool
|
|
17
|
+
|
|
18
|
+
@discardableResult
|
|
19
|
+
func save(string: String, key: String) -> Bool
|
|
20
|
+
|
|
21
|
+
@discardableResult
|
|
22
|
+
func save(data: Data, key: String) -> Bool
|
|
23
|
+
|
|
24
|
+
func model<T: Decodable>(for key: String) -> T?
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public struct Keychain: SecureStore {
|
|
28
|
+
private let service: String
|
|
29
|
+
|
|
30
|
+
public init(service: String) {
|
|
31
|
+
self.service = service
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public func string(for key: String) -> String? {
|
|
35
|
+
guard
|
|
36
|
+
let data = data(for: key),
|
|
37
|
+
let string = String(data: data, encoding: .utf8)
|
|
38
|
+
else { return nil }
|
|
39
|
+
return string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public func deleteData(for key: String) -> Bool {
|
|
43
|
+
let request = deletionRequestForKey(key)
|
|
44
|
+
let status: OSStatus = SecItemDelete(request)
|
|
45
|
+
return status == errSecSuccess
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public func deleteAll() -> Bool {
|
|
49
|
+
let request = deletionRequestForAll()
|
|
50
|
+
let status: OSStatus = SecItemDelete(request)
|
|
51
|
+
return status == errSecSuccess
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public func save(string: String, key: String) -> Bool {
|
|
55
|
+
guard let data = string.data(using: .utf8) else { return false }
|
|
56
|
+
return save(data: data, key: key)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@discardableResult
|
|
60
|
+
public func save(data: Data, key: String) -> Bool {
|
|
61
|
+
guard let attributes = attributes(for: data, key: key) else { return false }
|
|
62
|
+
|
|
63
|
+
let status: OSStatus = SecItemAdd(attributes, nil)
|
|
64
|
+
|
|
65
|
+
switch status {
|
|
66
|
+
case noErr:
|
|
67
|
+
return true
|
|
68
|
+
case errSecDuplicateItem:
|
|
69
|
+
guard deleteData(for: key) else { return false }
|
|
70
|
+
return save(data: data, key: key)
|
|
71
|
+
default:
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public func model<T: Decodable>(for key: String) -> T? {
|
|
77
|
+
guard
|
|
78
|
+
let data = data(for: key),
|
|
79
|
+
let model = try? JSONDecoder().decode(T.self, from: data)
|
|
80
|
+
else { return nil }
|
|
81
|
+
|
|
82
|
+
return model
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// MARK: Helper functions
|
|
86
|
+
|
|
87
|
+
public func data(for key: String) -> Data? {
|
|
88
|
+
let request = requestForKey(key)
|
|
89
|
+
var dataTypeRef: CFTypeRef?
|
|
90
|
+
let status: OSStatus = SecItemCopyMatching(request, &dataTypeRef)
|
|
91
|
+
|
|
92
|
+
switch status {
|
|
93
|
+
case errSecSuccess:
|
|
94
|
+
return dataTypeRef as? Data
|
|
95
|
+
default:
|
|
96
|
+
return nil
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private func requestForKey(_ key: String) -> CFDictionary {
|
|
101
|
+
[
|
|
102
|
+
kSecReturnData: true,
|
|
103
|
+
kSecAttrAccount: key,
|
|
104
|
+
kSecAttrService: service,
|
|
105
|
+
kSecMatchLimit: kSecMatchLimitOne,
|
|
106
|
+
kSecClass: kSecClassGenericPassword
|
|
107
|
+
] as CFDictionary
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private func deletionRequestForKey(_ key: String) -> CFDictionary {
|
|
111
|
+
[
|
|
112
|
+
kSecAttrAccount: key,
|
|
113
|
+
kSecAttrService: service,
|
|
114
|
+
kSecClass: kSecClassGenericPassword
|
|
115
|
+
] as CFDictionary
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
private func deletionRequestForAll() -> CFDictionary {
|
|
119
|
+
[
|
|
120
|
+
kSecAttrService: service,
|
|
121
|
+
kSecClass: kSecClassGenericPassword
|
|
122
|
+
] as CFDictionary
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private func attributes(for data: Data, key: String) -> CFDictionary? {
|
|
126
|
+
[
|
|
127
|
+
kSecValueData: data,
|
|
128
|
+
kSecAttrAccount: key,
|
|
129
|
+
kSecAttrService: service,
|
|
130
|
+
kSecClass: kSecClassGenericPassword,
|
|
131
|
+
kSecAttrAccessible: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
|
|
132
|
+
] as CFDictionary
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SessionConfig.swift
|
|
3
|
+
// metamask-ios-sdk
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
public class SessionConfig: Codable, Equatable {
|
|
9
|
+
public static func == (lhs: SessionConfig, rhs: SessionConfig) -> Bool {
|
|
10
|
+
lhs.sessionId == rhs.sessionId && lhs.expiry == rhs.expiry
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
public let sessionId: String
|
|
14
|
+
public let expiry: Date
|
|
15
|
+
|
|
16
|
+
public var isValid: Bool {
|
|
17
|
+
expiry > Date()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public init(sessionId: String, expiry: Date) {
|
|
21
|
+
self.sessionId = sessionId
|
|
22
|
+
self.expiry = expiry
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SessionManager.swift
|
|
3
|
+
// metamask-ios-sdk
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
public class SessionManager {
|
|
9
|
+
private let store: SecureStore
|
|
10
|
+
private let SESSION_KEY = "session_id"
|
|
11
|
+
private let DEFAULT_SESSION_DURATION: TimeInterval = 24 * 7 * 3600
|
|
12
|
+
|
|
13
|
+
public var sessionDuration: TimeInterval
|
|
14
|
+
|
|
15
|
+
public init(store: SecureStore,
|
|
16
|
+
sessionDuration: TimeInterval) {
|
|
17
|
+
self.store = store
|
|
18
|
+
self.sessionDuration = sessionDuration
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public func fetchCurrentSessionConfig() -> SessionConfig? {
|
|
22
|
+
let config: SessionConfig? = store.model(for: SESSION_KEY)
|
|
23
|
+
return config
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public func createNewSessionConfig() {
|
|
27
|
+
// update session expiry date
|
|
28
|
+
let config = SessionConfig(sessionId: UUID().uuidString.lowercased(),
|
|
29
|
+
expiry: Date(timeIntervalSinceNow: sessionDuration))
|
|
30
|
+
if !config.isValid {
|
|
31
|
+
sessionDuration = DEFAULT_SESSION_DURATION
|
|
32
|
+
createNewSessionConfig()
|
|
33
|
+
}
|
|
34
|
+
// persist session config
|
|
35
|
+
if let configData = try? JSONEncoder().encode(config) {
|
|
36
|
+
store.save(data: configData, key: SESSION_KEY)
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public func fetchSessionConfig() -> (SessionConfig, Bool) {
|
|
41
|
+
|
|
42
|
+
if let config = fetchCurrentSessionConfig(), config.isValid {
|
|
43
|
+
return (config, true)
|
|
44
|
+
} else {
|
|
45
|
+
// purge any existing session info
|
|
46
|
+
store.deleteData(for: SESSION_KEY)
|
|
47
|
+
createNewSessionConfig()
|
|
48
|
+
let config = fetchSessionConfig().0
|
|
49
|
+
return (config, false)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public func clear() {
|
|
54
|
+
store.deleteAll()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Dependencies.swift
|
|
3
|
+
// metamask-ios-sdk
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
public final class Dependencies {
|
|
9
|
+
public static let shared = Dependencies()
|
|
10
|
+
|
|
11
|
+
public lazy var store: SecureStore = Keychain(service: SDKInfo.bundleIdentifier ?? UUID().uuidString)
|
|
12
|
+
public lazy var sessionManager: SessionManager = SessionManager(store: store, sessionDuration: 24 * 3600 * 30)
|
|
13
|
+
|
|
14
|
+
public lazy var commClientFactory: CommClientFactory = CommClientFactory()
|
|
15
|
+
|
|
16
|
+
public func ethereum(transport: Transport, sdkOptions: SDKOptions?) -> Ethereum {
|
|
17
|
+
Ethereum.shared(
|
|
18
|
+
transport: transport,
|
|
19
|
+
store: store,
|
|
20
|
+
commClientFactory: commClientFactory
|
|
21
|
+
).updateTransportLayer(transport)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public lazy var keyExchange: KeyExchange = KeyExchange(storage: store)
|
|
25
|
+
|
|
26
|
+
public lazy var deeplinkManager: DeeplinkManager = DeeplinkManager()
|
|
27
|
+
|
|
28
|
+
public func deeplinkClient(dappScheme: String) -> DeeplinkClient {
|
|
29
|
+
DeeplinkClient(
|
|
30
|
+
session: sessionManager,
|
|
31
|
+
keyExchange: keyExchange,
|
|
32
|
+
deeplinkManager: deeplinkManager,
|
|
33
|
+
dappScheme: dappScheme)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
//
|
|
2
|
+
// MetaMaskSDK.swift
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import SwiftUI
|
|
6
|
+
import UIKit
|
|
7
|
+
import Combine
|
|
8
|
+
import Foundation
|
|
9
|
+
|
|
10
|
+
class SDKWrapper {
|
|
11
|
+
var sdk: MetaMaskSDK?
|
|
12
|
+
static let shared = SDKWrapper()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public class MetaMaskSDK: ObservableObject {
|
|
16
|
+
private var ethereum: Ethereum!
|
|
17
|
+
|
|
18
|
+
/// The active/selected MetaMask account chain
|
|
19
|
+
@Published public var chainId: String = ""
|
|
20
|
+
/// Indicated whether connected to MetaMask
|
|
21
|
+
@Published public var connected: Bool = false
|
|
22
|
+
|
|
23
|
+
/// The active/selected MetaMask account address
|
|
24
|
+
@Published public var account: String = ""
|
|
25
|
+
|
|
26
|
+
public static var sharedInstance: MetaMaskSDK? = SDKWrapper.shared.sdk
|
|
27
|
+
|
|
28
|
+
public var transport: Transport
|
|
29
|
+
|
|
30
|
+
public var networkUrl: String {
|
|
31
|
+
get {
|
|
32
|
+
(ethereum.commClient as? SocketClient)?.networkUrl ?? ""
|
|
33
|
+
} set {
|
|
34
|
+
(ethereum.commClient as? SocketClient)?.networkUrl = newValue
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public var useDeeplinks: Bool = false {
|
|
39
|
+
didSet {
|
|
40
|
+
(ethereum.commClient as? SocketClient)?.useDeeplinks = useDeeplinks
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public var sessionDuration: TimeInterval {
|
|
45
|
+
get {
|
|
46
|
+
ethereum.commClient.sessionDuration
|
|
47
|
+
} set {
|
|
48
|
+
ethereum.commClient.sessionDuration = newValue
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private init(appMetadata: AppMetadata, transport: Transport, enableDebug: Bool, sdkOptions: SDKOptions?) {
|
|
53
|
+
self.ethereum = Dependencies.shared.ethereum(transport: transport, sdkOptions: sdkOptions)
|
|
54
|
+
self.transport = transport
|
|
55
|
+
self.ethereum.delegate = self
|
|
56
|
+
self.ethereum.updateMetadata(appMetadata)
|
|
57
|
+
self.account = ethereum.account
|
|
58
|
+
self.chainId = ethereum.chainId
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public var isMetaMaskInstalled: Bool {
|
|
62
|
+
guard let url = URL(string: "metamask://") else {
|
|
63
|
+
return false
|
|
64
|
+
}
|
|
65
|
+
return UIApplication.shared.canOpenURL(url)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public func handleUrl(_ url: URL) {
|
|
69
|
+
(ethereum.commClient as? DeeplinkClient)?.handleUrl(url)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public static func shared(_ appMetadata: AppMetadata,
|
|
73
|
+
transport: Transport,
|
|
74
|
+
enableDebug: Bool = true,
|
|
75
|
+
sdkOptions: SDKOptions?) -> MetaMaskSDK {
|
|
76
|
+
guard let sdk = SDKWrapper.shared.sdk else {
|
|
77
|
+
let metamaskSdk = MetaMaskSDK(
|
|
78
|
+
appMetadata: appMetadata,
|
|
79
|
+
transport: transport,
|
|
80
|
+
enableDebug: enableDebug,
|
|
81
|
+
sdkOptions: sdkOptions)
|
|
82
|
+
SDKWrapper.shared.sdk = metamaskSdk
|
|
83
|
+
return metamaskSdk
|
|
84
|
+
}
|
|
85
|
+
return sdk
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public func updateTransportLayer(_ transport: Transport) {
|
|
89
|
+
self.ethereum.updateTransportLayer(transport)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public extension MetaMaskSDK {
|
|
94
|
+
func connect() async -> Result<[String], RequestError> {
|
|
95
|
+
await ethereum.connect()
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func connectAndSign(message: String) async -> Result<String, RequestError> {
|
|
99
|
+
await ethereum.connectAndSign(message: message)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func connectWith<T: CodableData>(_ request: EthereumRequest<T>) async -> Result<String, RequestError> {
|
|
103
|
+
await ethereum.connectWith(request)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func disconnect() {
|
|
107
|
+
ethereum.disconnect()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func clearSession() {
|
|
111
|
+
ethereum.clearSession()
|
|
112
|
+
connected = false
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func terminateConnection() {
|
|
116
|
+
ethereum.terminateConnection()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
func request<T: CodableData>(_ request: EthereumRequest<T>) async -> Result<String, RequestError> {
|
|
120
|
+
await ethereum.request(request)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
func batchRequest<T: CodableData>(_ requests: [EthereumRequest<T>]) async -> Result<[String], RequestError> {
|
|
124
|
+
await ethereum.batchRequest(requests)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
func getChainId() async -> Result<String, RequestError> {
|
|
128
|
+
await ethereum.getChainId()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
func getEthAccounts() async -> Result<[String], RequestError> {
|
|
132
|
+
await ethereum.getEthAccounts()
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
func getEthGasPrice() async -> Result<String, RequestError> {
|
|
136
|
+
await ethereum.getEthGasPrice()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func getEthBalance(address: String, block: String) async -> Result<String, RequestError> {
|
|
140
|
+
await ethereum.getEthBalance(address: address, block: block)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
func getEthBlockNumber() async -> Result<String, RequestError> {
|
|
144
|
+
await ethereum.getEthBlockNumber()
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
func getEthEstimateGas() async -> Result<String, RequestError> {
|
|
148
|
+
await ethereum.getEthEstimateGas()
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
func getWeb3ClientVersion() async -> Result<String, RequestError> {
|
|
152
|
+
await ethereum.getWeb3ClientVersion()
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
func personalSign(message: String, address: String) async -> Result<String, RequestError> {
|
|
156
|
+
await ethereum.personalSign(message: message, address: address)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
func signTypedDataV4(typedData: String, address: String) async -> Result<String, RequestError> {
|
|
160
|
+
await ethereum.signTypedDataV4(typedData: typedData, address: address)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
func sendTransaction(from: String, to: String, value: String) async -> Result<String, RequestError> {
|
|
164
|
+
await ethereum.sendTransaction(from: from, to: to, value: value)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func sendRawTransaction(signedTransaction: String) async -> Result<String, RequestError> {
|
|
168
|
+
await ethereum.sendRawTransaction(signedTransaction: signedTransaction)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func getBlockTransactionCountByNumber(blockNumber: String) async -> Result<String, RequestError> {
|
|
172
|
+
await ethereum.getBlockTransactionCountByNumber(blockNumber: blockNumber)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
func getBlockTransactionCountByHash(blockHash: String) async -> Result<String, RequestError> {
|
|
176
|
+
await ethereum.getBlockTransactionCountByHash(blockHash: blockHash)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
func getTransactionCount(address: String, tagOrblockNumber: String) async -> Result<String, RequestError> {
|
|
180
|
+
await ethereum.getTransactionCount(address: address, tagOrblockNumber: tagOrblockNumber)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
func addEthereumChain(chainId: String,
|
|
184
|
+
chainName: String,
|
|
185
|
+
rpcUrls: [String],
|
|
186
|
+
iconUrls: [String]?,
|
|
187
|
+
blockExplorerUrls: [String]?,
|
|
188
|
+
nativeCurrency: NativeCurrency) async -> Result<String, RequestError> {
|
|
189
|
+
await ethereum.addEthereumChain(
|
|
190
|
+
chainId: chainId,
|
|
191
|
+
chainName: chainName,
|
|
192
|
+
rpcUrls: rpcUrls,
|
|
193
|
+
iconUrls: iconUrls,
|
|
194
|
+
blockExplorerUrls: blockExplorerUrls,
|
|
195
|
+
nativeCurrency: nativeCurrency
|
|
196
|
+
)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
func switchEthereumChain(chainId: String) async -> Result<String, RequestError> {
|
|
200
|
+
await ethereum.switchEthereumChain(chainId: chainId)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
extension MetaMaskSDK: EthereumEventsDelegate {
|
|
205
|
+
func chainIdChanged(_ chainId: String) {
|
|
206
|
+
self.chainId = chainId
|
|
207
|
+
NotificationCenter.default.post(name: .MetaMaskChainIdChanged, object: nil, userInfo: ["chainId": chainId])
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
func accountChanged(_ account: String) {
|
|
211
|
+
self.account = account
|
|
212
|
+
connected = true
|
|
213
|
+
NotificationCenter.default.post(name: .MetaMaskAccountChanged, object: nil, userInfo: ["account": account])
|
|
214
|
+
}
|
|
215
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SDKInfo.swift
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import UIKit
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
public enum SDKInfo {
|
|
9
|
+
/// Bundle with SDK plist
|
|
10
|
+
public static var sdkBundle: [String: Any] {
|
|
11
|
+
Bundle(for: MetaMaskSDK.self).infoDictionary ?? [:]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/// The version number of the SDK e.g `1.0.0`
|
|
15
|
+
public static var version: String {
|
|
16
|
+
sdkBundle["CFBundleShortVersionString"] as? String ?? ""
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/// The bundle identifier of the dapp
|
|
20
|
+
public static var bundleIdentifier: String? {
|
|
21
|
+
Bundle.main.bundleIdentifier
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// The platform OS on which the SDK is run e.g `ios, ipados`
|
|
25
|
+
public static var platform: String {
|
|
26
|
+
UIDevice.current.systemName.lowercased()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Checks if Dapp is configured for Deeplink communication layer
|
|
30
|
+
public static func isConfiguredForURLScheme(_ scheme: String) -> Bool {
|
|
31
|
+
guard let urlTypes = sdkBundle["CFBundleURLTypes"] as? [AnyObject],
|
|
32
|
+
let urlTypeDictionary = urlTypes.first as? [String: AnyObject],
|
|
33
|
+
let urlSchemes = urlTypeDictionary["CFBundleURLSchemes"] as? [String]
|
|
34
|
+
else { return false }
|
|
35
|
+
return urlSchemes.contains(scheme)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// SDKOptions.swift
|
|
3
|
+
// metamask-ios-sdk
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import Foundation
|
|
7
|
+
|
|
8
|
+
public struct SDKOptions {
|
|
9
|
+
public let infuraAPIKey: String
|
|
10
|
+
public let readonlyRPCMap: [String: String]
|
|
11
|
+
|
|
12
|
+
public init(infuraAPIKey: String, readonlyRPCMap: [String: String] = [:]) {
|
|
13
|
+
self.infuraAPIKey = infuraAPIKey
|
|
14
|
+
self.readonlyRPCMap = readonlyRPCMap
|
|
15
|
+
}
|
|
16
|
+
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -4,17 +4,64 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.NitroMetamask = void 0;
|
|
7
|
+
exports.parseNitroError = parseNitroError;
|
|
7
8
|
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
8
9
|
/**
|
|
9
10
|
* NitroMetamask - MetaMask connector for React Native
|
|
10
|
-
*
|
|
11
|
+
*
|
|
12
|
+
* Provides native MetaMask wallet integration via Nitro modules.
|
|
13
|
+
*
|
|
11
14
|
* @example
|
|
12
15
|
* ```ts
|
|
13
16
|
* import { NitroMetamask } from '@novastera-oss/nitro-metamask'
|
|
14
|
-
*
|
|
15
|
-
*
|
|
17
|
+
*
|
|
18
|
+
* // Optional: configure before use
|
|
19
|
+
* NitroMetamask.configure('https://yourdomain.com', 'yourscheme')
|
|
20
|
+
*
|
|
21
|
+
* // Connect wallet
|
|
22
|
+
* const { address, chainId } = await NitroMetamask.connect()
|
|
23
|
+
*
|
|
24
|
+
* // Sign a message
|
|
16
25
|
* const signature = await NitroMetamask.signMessage('Hello')
|
|
26
|
+
*
|
|
27
|
+
* // Connect and sign in one step (SIWE)
|
|
28
|
+
* const result = await NitroMetamask.connectSign('my-nonce', BigInt(Date.now()))
|
|
17
29
|
* ```
|
|
18
30
|
*/
|
|
19
31
|
const NitroMetamask = exports.NitroMetamask = _reactNativeNitroModules.NitroModules.createHybridObject('NitroMetamask');
|
|
32
|
+
/**
|
|
33
|
+
* Parses a structured Nitro error message that contains a numeric error code prefix.
|
|
34
|
+
*
|
|
35
|
+
* Nitro errors from the native layer are formatted as `"[<code>] <message>"`.
|
|
36
|
+
* This utility extracts the code and message so the JS layer can handle them
|
|
37
|
+
* programmatically (e.g., detecting `code: 2` for MetaMask not installed).
|
|
38
|
+
*
|
|
39
|
+
* @param e - The error to parse. Can be an `Error`, a string, or any value.
|
|
40
|
+
* @returns An object `{ code: number; message: string }` if the error message
|
|
41
|
+
* matches the `[code] message` pattern, or `null` if it does not.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* import { parseNitroError } from '@novastera-oss/nitro-metamask'
|
|
46
|
+
*
|
|
47
|
+
* try {
|
|
48
|
+
* await NitroMetamask.connect()
|
|
49
|
+
* } catch (e) {
|
|
50
|
+
* const parsed = parseNitroError(e)
|
|
51
|
+
* if (parsed?.code === 2) {
|
|
52
|
+
* // MetaMask is not installed — redirect user to App Store / Play Store
|
|
53
|
+
* }
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
function parseNitroError(e) {
|
|
58
|
+
const raw = e instanceof Error ? e.message : typeof e === 'string' ? e : null;
|
|
59
|
+
if (raw === null) return null;
|
|
60
|
+
const match = raw.match(/^\[(\d+)\]\s*(.*)/);
|
|
61
|
+
if (!match) return null;
|
|
62
|
+
return {
|
|
63
|
+
code: Number(match[1]),
|
|
64
|
+
message: match[2] ?? ''
|
|
65
|
+
};
|
|
66
|
+
}
|
|
20
67
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNativeNitroModules","require","NitroMetamask","exports","NitroModules","createHybridObject"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_reactNativeNitroModules","require","NitroMetamask","exports","NitroModules","createHybridObject","parseNitroError","e","raw","Error","message","match","code","Number"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,aAAa,GAAAC,OAAA,CAAAD,aAAA,GAAGE,qCAAY,CAACC,kBAAkB,CAAoB,eAAe,CAAC;AAIhG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,eAAeA,CAACC,CAAU,EAA4C;EACpF,MAAMC,GAAG,GAAGD,CAAC,YAAYE,KAAK,GAAGF,CAAC,CAACG,OAAO,GAAG,OAAOH,CAAC,KAAK,QAAQ,GAAGA,CAAC,GAAG,IAAI;EAC7E,IAAIC,GAAG,KAAK,IAAI,EAAE,OAAO,IAAI;EAC7B,MAAMG,KAAK,GAAGH,GAAG,CAACG,KAAK,CAAC,mBAAmB,CAAC;EAC5C,IAAI,CAACA,KAAK,EAAE,OAAO,IAAI;EACvB,OAAO;IAAEC,IAAI,EAAEC,MAAM,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;IAAED,OAAO,EAAEC,KAAK,CAAC,CAAC,CAAC,IAAI;EAAG,CAAC;AAC5D","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -3,14 +3,60 @@
|
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules';
|
|
4
4
|
/**
|
|
5
5
|
* NitroMetamask - MetaMask connector for React Native
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* Provides native MetaMask wallet integration via Nitro modules.
|
|
8
|
+
*
|
|
7
9
|
* @example
|
|
8
10
|
* ```ts
|
|
9
11
|
* import { NitroMetamask } from '@novastera-oss/nitro-metamask'
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* // Optional: configure before use
|
|
14
|
+
* NitroMetamask.configure('https://yourdomain.com', 'yourscheme')
|
|
15
|
+
*
|
|
16
|
+
* // Connect wallet
|
|
17
|
+
* const { address, chainId } = await NitroMetamask.connect()
|
|
18
|
+
*
|
|
19
|
+
* // Sign a message
|
|
12
20
|
* const signature = await NitroMetamask.signMessage('Hello')
|
|
21
|
+
*
|
|
22
|
+
* // Connect and sign in one step (SIWE)
|
|
23
|
+
* const result = await NitroMetamask.connectSign('my-nonce', BigInt(Date.now()))
|
|
13
24
|
* ```
|
|
14
25
|
*/
|
|
15
26
|
export const NitroMetamask = NitroModules.createHybridObject('NitroMetamask');
|
|
27
|
+
/**
|
|
28
|
+
* Parses a structured Nitro error message that contains a numeric error code prefix.
|
|
29
|
+
*
|
|
30
|
+
* Nitro errors from the native layer are formatted as `"[<code>] <message>"`.
|
|
31
|
+
* This utility extracts the code and message so the JS layer can handle them
|
|
32
|
+
* programmatically (e.g., detecting `code: 2` for MetaMask not installed).
|
|
33
|
+
*
|
|
34
|
+
* @param e - The error to parse. Can be an `Error`, a string, or any value.
|
|
35
|
+
* @returns An object `{ code: number; message: string }` if the error message
|
|
36
|
+
* matches the `[code] message` pattern, or `null` if it does not.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* import { parseNitroError } from '@novastera-oss/nitro-metamask'
|
|
41
|
+
*
|
|
42
|
+
* try {
|
|
43
|
+
* await NitroMetamask.connect()
|
|
44
|
+
* } catch (e) {
|
|
45
|
+
* const parsed = parseNitroError(e)
|
|
46
|
+
* if (parsed?.code === 2) {
|
|
47
|
+
* // MetaMask is not installed — redirect user to App Store / Play Store
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function parseNitroError(e) {
|
|
53
|
+
const raw = e instanceof Error ? e.message : typeof e === 'string' ? e : null;
|
|
54
|
+
if (raw === null) return null;
|
|
55
|
+
const match = raw.match(/^\[(\d+)\]\s*(.*)/);
|
|
56
|
+
if (!match) return null;
|
|
57
|
+
return {
|
|
58
|
+
code: Number(match[1]),
|
|
59
|
+
message: match[2] ?? ''
|
|
60
|
+
};
|
|
61
|
+
}
|
|
16
62
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NitroModules","NitroMetamask","createHybridObject"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;
|
|
1
|
+
{"version":3,"names":["NitroModules","NitroMetamask","createHybridObject","parseNitroError","e","raw","Error","message","match","code","Number"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAOzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,aAAa,GAAGD,YAAY,CAACE,kBAAkB,CAAoB,eAAe,CAAC;AAIhG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,CAAU,EAA4C;EACpF,MAAMC,GAAG,GAAGD,CAAC,YAAYE,KAAK,GAAGF,CAAC,CAACG,OAAO,GAAG,OAAOH,CAAC,KAAK,QAAQ,GAAGA,CAAC,GAAG,IAAI;EAC7E,IAAIC,GAAG,KAAK,IAAI,EAAE,OAAO,IAAI;EAC7B,MAAMG,KAAK,GAAGH,GAAG,CAACG,KAAK,CAAC,mBAAmB,CAAC;EAC5C,IAAI,CAACA,KAAK,EAAE,OAAO,IAAI;EACvB,OAAO;IAAEC,IAAI,EAAEC,MAAM,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;IAAED,OAAO,EAAEC,KAAK,CAAC,CAAC,CAAC,IAAI;EAAG,CAAC;AAC5D","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseNitroError.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/parseNitroError.test.ts"],"names":[],"mappings":""}
|