@getpara/react-native-wallet 2.0.0-alpha.3 → 2.0.0-alpha.30
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/dist/AsyncStorage.d.ts +2 -5
- package/dist/AsyncStorage.js +37 -14
- package/dist/KeychainStorage.d.ts +0 -3
- package/dist/KeychainStorage.js +35 -28
- package/dist/config.d.ts +3 -0
- package/dist/config.js +1 -0
- package/dist/react-native/ParaMobile.d.ts +3 -1
- package/dist/react-native/ParaMobile.js +22 -12
- package/dist/react-native/ReactNativeUtils.d.ts +3 -2
- package/dist/react-native/ReactNativeUtils.js +8 -7
- package/dist/shim.js +7 -0
- package/package.json +62 -29
- package/src/AsyncStorage.ts +32 -14
- package/src/KeychainStorage.ts +34 -31
- package/src/config.ts +2 -0
- package/src/react-native/ParaMobile.ts +24 -16
- package/src/react-native/ReactNativeUtils.ts +9 -8
- package/src/shim.js +8 -0
- /package/src/{index.tsx → index.ts} +0 -0
package/dist/AsyncStorage.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { StorageUtils } from '@getpara/web-sdk';
|
|
2
|
-
/**
|
|
3
|
-
* Implements `StorageUtils` using React Native Async Storage.
|
|
4
|
-
*/
|
|
5
2
|
export declare class AsyncStorage implements StorageUtils {
|
|
6
|
-
clear(prefix: string): Promise<void>;
|
|
7
3
|
get(key: string): Promise<string | null>;
|
|
8
|
-
removeItem(key: string): Promise<void>;
|
|
9
4
|
set(key: string, value: string): Promise<void>;
|
|
5
|
+
removeItem(key: string): Promise<void>;
|
|
6
|
+
clear(prefix: string): Promise<void>;
|
|
10
7
|
}
|
package/dist/AsyncStorage.js
CHANGED
|
@@ -8,33 +8,56 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import RNAsyncStorage from '@react-native-async-storage/async-storage';
|
|
11
|
-
/**
|
|
12
|
-
* Implements `StorageUtils` using React Native Async Storage.
|
|
13
|
-
*/
|
|
14
11
|
export class AsyncStorage {
|
|
15
|
-
|
|
12
|
+
get(key) {
|
|
16
13
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
try {
|
|
15
|
+
return yield RNAsyncStorage.getItem(key);
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.warn('Error retrieving stored item:', error);
|
|
19
|
+
return null;
|
|
22
20
|
}
|
|
23
21
|
});
|
|
24
22
|
}
|
|
25
|
-
|
|
23
|
+
set(key, value) {
|
|
26
24
|
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
-
|
|
25
|
+
try {
|
|
26
|
+
yield RNAsyncStorage.setItem(key, value);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.warn(`Error storing key ${key}:`, error);
|
|
30
|
+
}
|
|
28
31
|
});
|
|
29
32
|
}
|
|
30
33
|
removeItem(key) {
|
|
31
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
|
|
35
|
+
try {
|
|
36
|
+
yield RNAsyncStorage.removeItem(key);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.warn(`Error removing key ${key}:`, error);
|
|
40
|
+
}
|
|
33
41
|
});
|
|
34
42
|
}
|
|
35
|
-
|
|
43
|
+
clear(prefix) {
|
|
36
44
|
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
-
|
|
45
|
+
try {
|
|
46
|
+
const keys = yield RNAsyncStorage.getAllKeys();
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
if (key.startsWith(prefix)) {
|
|
49
|
+
try {
|
|
50
|
+
yield RNAsyncStorage.removeItem(key);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.warn(`Error clearing key ${key}:`, error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
console.warn(`Error getting keys for prefix ${prefix}:`, error);
|
|
60
|
+
}
|
|
38
61
|
});
|
|
39
62
|
}
|
|
40
63
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
import { StorageUtils } from '@getpara/web-sdk';
|
|
2
|
-
/**
|
|
3
|
-
* Implements `StorageUtils` using React Native `Keychain`.
|
|
4
|
-
*/
|
|
5
2
|
export declare class KeychainStorage implements StorageUtils {
|
|
6
3
|
get(key: string): Promise<string | null>;
|
|
7
4
|
set(key: string, value: string): Promise<void>;
|
package/dist/KeychainStorage.js
CHANGED
|
@@ -9,17 +9,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import Keychain from 'react-native-keychain';
|
|
11
11
|
const USERNAME = '@CAPSULE';
|
|
12
|
-
const KEYCHAIN_USER_CANCELLED_ERRORS = [
|
|
13
|
-
'user canceled the operation',
|
|
14
|
-
'error: code: 13, msg: cancel',
|
|
15
|
-
'error: code: 10, msg: fingerprint operation canceled by the user',
|
|
16
|
-
];
|
|
17
|
-
function isUserCancelledError(error) {
|
|
18
|
-
return KEYCHAIN_USER_CANCELLED_ERRORS.some(userCancelledError => error.toString().toLowerCase().includes(userCancelledError));
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Implements `StorageUtils` using React Native `Keychain`.
|
|
22
|
-
*/
|
|
23
12
|
export class KeychainStorage {
|
|
24
13
|
get(key) {
|
|
25
14
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -33,39 +22,57 @@ export class KeychainStorage {
|
|
|
33
22
|
return item.password;
|
|
34
23
|
}
|
|
35
24
|
catch (error) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
throw new Error('Error retrieving stored item ' + error.message);
|
|
39
|
-
}
|
|
40
|
-
throw error;
|
|
25
|
+
console.warn('Error retrieving stored item:', error);
|
|
26
|
+
return null;
|
|
41
27
|
}
|
|
42
28
|
});
|
|
43
29
|
}
|
|
44
30
|
set(key, value) {
|
|
45
31
|
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
try {
|
|
33
|
+
const result = yield Keychain.setGenericPassword(USERNAME, value, {
|
|
34
|
+
service: key,
|
|
35
|
+
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
|
|
36
|
+
securityLevel: Keychain.SECURITY_LEVEL.ANY,
|
|
37
|
+
storage: Keychain.STORAGE_TYPE.AES_GCM_NO_AUTH,
|
|
38
|
+
});
|
|
39
|
+
if (!result) {
|
|
40
|
+
console.warn(`Failed to store key ${key}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.warn(`Error storing key ${key}:`, error);
|
|
53
45
|
}
|
|
54
46
|
});
|
|
55
47
|
}
|
|
56
48
|
removeItem(key) {
|
|
57
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
|
|
50
|
+
try {
|
|
51
|
+
yield Keychain.resetGenericPassword({ service: key });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.warn(`Error removing key ${key}:`, error);
|
|
55
|
+
}
|
|
59
56
|
});
|
|
60
57
|
}
|
|
61
58
|
clear(prefix) {
|
|
62
59
|
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
try {
|
|
61
|
+
const services = yield Keychain.getAllGenericPasswordServices();
|
|
62
|
+
for (const key of services) {
|
|
63
|
+
if (key && key.startsWith(prefix)) {
|
|
64
|
+
try {
|
|
65
|
+
yield Keychain.resetGenericPassword({ service: key });
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
console.warn(`Error clearing key ${key}:`, error);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.warn(`Error getting services for prefix ${prefix}:`, error);
|
|
75
|
+
}
|
|
69
76
|
});
|
|
70
77
|
}
|
|
71
78
|
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Environment } from '@getpara/web-sdk';
|
|
2
|
+
declare function getPortalBaseURL(env: Environment): "http://localhost:3003" | "https://app.sandbox.usecapsule.com" | "https://app.beta.usecapsule.com" | "https://app.usecapsule.com";
|
|
3
|
+
declare function getBaseUrl(env: Environment): string;
|
|
2
4
|
export declare function getBaseMPCNetworkWSUrl(env: Environment): string;
|
|
3
5
|
export declare let userManagementServer: string;
|
|
4
6
|
export declare let portalBase: string;
|
|
5
7
|
export declare let mpcNetworkWSServer: string;
|
|
6
8
|
export declare function setEnv(env: Environment): void;
|
|
7
9
|
export declare const DEBUG_MODE_ENABLED = false;
|
|
10
|
+
export { getBaseUrl, getPortalBaseURL };
|
package/dist/config.js
CHANGED
|
@@ -17,7 +17,9 @@ export declare class ParaMobile extends ParaCore {
|
|
|
17
17
|
* @param {ConstructorOpts} [opts] - Additional constructor options.
|
|
18
18
|
*/
|
|
19
19
|
constructor(env: Environment, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts);
|
|
20
|
+
protected ready(): Promise<void>;
|
|
20
21
|
protected getPlatformUtils(): PlatformUtils;
|
|
22
|
+
isPasskeySupported(): Promise<boolean>;
|
|
21
23
|
/**
|
|
22
24
|
* Registers a passkey for the user.
|
|
23
25
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -30,5 +32,5 @@ export declare class ParaMobile extends ParaCore {
|
|
|
30
32
|
* @param {AuthParams} params - The authentication parameters.
|
|
31
33
|
* @returns {Promise<void>}
|
|
32
34
|
*/
|
|
33
|
-
|
|
35
|
+
loginWithPasskey(): Promise<void>;
|
|
34
36
|
}
|
|
@@ -8,7 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { ParaCore, Environment, decryptPrivateKeyAndDecryptShare, encryptPrivateKey, getAsymmetricKeyPair, getDerivedPrivateKeyAndDecrypt, getPublicKeyHex, getSHA256HashHex, parseCredentialCreationRes, } from '@getpara/web-sdk';
|
|
11
|
-
import * as Sentry from '@sentry/react-native';
|
|
12
11
|
import { ReactNativeUtils } from './ReactNativeUtils.js';
|
|
13
12
|
import { Passkey, } from 'react-native-passkey';
|
|
14
13
|
import { PublicKeyStatus } from '@getpara/user-management-client';
|
|
@@ -35,14 +34,6 @@ export class ParaMobile extends ParaCore {
|
|
|
35
34
|
constructor(env, apiKey, relyingPartyId, opts) {
|
|
36
35
|
super(env, apiKey, opts);
|
|
37
36
|
this.isNativePasskey = true;
|
|
38
|
-
// starting with non-prod to see what kind of errors we get and if sensitive data is tracked
|
|
39
|
-
// will turn on in prod after monitoring
|
|
40
|
-
if (env !== Environment.PROD && env !== Environment.DEV) {
|
|
41
|
-
Sentry.init({
|
|
42
|
-
environment: env.toLowerCase(),
|
|
43
|
-
dsn: 'https://59cea0cfbbb30a646c4e9f2feea06da4@o4504568036720640.ingest.us.sentry.io/4508850922323968',
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
37
|
setEnv(env);
|
|
47
38
|
if (relyingPartyId) {
|
|
48
39
|
this.relyingPartyId = relyingPartyId;
|
|
@@ -63,9 +54,19 @@ export class ParaMobile extends ParaCore {
|
|
|
63
54
|
}
|
|
64
55
|
}
|
|
65
56
|
}
|
|
57
|
+
ready() {
|
|
58
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
59
|
+
this.isReady = true;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
66
62
|
getPlatformUtils() {
|
|
67
63
|
return new ReactNativeUtils();
|
|
68
64
|
}
|
|
65
|
+
isPasskeySupported() {
|
|
66
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
67
|
+
return Passkey.isSupported();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
69
70
|
/**
|
|
70
71
|
* Registers a passkey for the user.
|
|
71
72
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -144,7 +145,7 @@ export class ParaMobile extends ParaCore {
|
|
|
144
145
|
* @param {AuthParams} params - The authentication parameters.
|
|
145
146
|
* @returns {Promise<void>}
|
|
146
147
|
*/
|
|
147
|
-
|
|
148
|
+
loginWithPasskey() {
|
|
148
149
|
return __awaiter(this, void 0, void 0, function* () {
|
|
149
150
|
this.assertIsAuthSet();
|
|
150
151
|
const userId = this.assertUserId();
|
|
@@ -163,7 +164,7 @@ export class ParaMobile extends ParaCore {
|
|
|
163
164
|
else {
|
|
164
165
|
resultJson = result;
|
|
165
166
|
}
|
|
166
|
-
const { partnerId } = yield this.ctx.client.touchSession();
|
|
167
|
+
const { partnerId, sessionLookupId } = yield this.ctx.client.touchSession();
|
|
167
168
|
const publicKey = resultJson.id;
|
|
168
169
|
const verifyWebChallengeResult = yield this.ctx.client.verifyWebChallenge(partnerId, {
|
|
169
170
|
publicKey,
|
|
@@ -173,7 +174,7 @@ export class ParaMobile extends ParaCore {
|
|
|
173
174
|
signature: resultJson.response.signature,
|
|
174
175
|
},
|
|
175
176
|
});
|
|
176
|
-
if (userId !== verifyWebChallengeResult.userId) {
|
|
177
|
+
if (userId !== verifyWebChallengeResult.data.userId) {
|
|
177
178
|
throw new Error('User ID mismatch');
|
|
178
179
|
}
|
|
179
180
|
const encryptedSharesResult = yield this.ctx.client.getBiometricKeyshares(userId, resultJson.id);
|
|
@@ -203,7 +204,16 @@ export class ParaMobile extends ParaCore {
|
|
|
203
204
|
type: desiredWallet.type || undefined,
|
|
204
205
|
};
|
|
205
206
|
}
|
|
207
|
+
const currentWalletIds = {};
|
|
208
|
+
for (const wallet of Object.values(walletsToInsert)) {
|
|
209
|
+
const { id, type } = wallet;
|
|
210
|
+
const currentIdsForType = currentWalletIds[type || 'EVM'] || [];
|
|
211
|
+
currentWalletIds[type || 'EVM'] = [...currentIdsForType, id];
|
|
212
|
+
}
|
|
206
213
|
yield this.setWallets(walletsToInsert);
|
|
214
|
+
yield this.setCurrentWalletIds(currentWalletIds, {
|
|
215
|
+
sessionLookupId,
|
|
216
|
+
});
|
|
207
217
|
});
|
|
208
218
|
}
|
|
209
219
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { PlatformUtils, TPregenIdentifierType } from '@getpara/web-sdk';
|
|
2
2
|
import { Ctx } from '@getpara/web-sdk';
|
|
3
3
|
import { SignatureRes } from '@getpara/web-sdk';
|
|
4
|
-
import { BackupKitEmailProps,
|
|
4
|
+
import { BackupKitEmailProps, TWalletType, SDKType } from '@getpara/user-management-client';
|
|
5
5
|
import { AsyncStorage } from '../AsyncStorage.js';
|
|
6
6
|
import { KeychainStorage } from '../KeychainStorage.js';
|
|
7
7
|
export declare class ReactNativeUtils implements PlatformUtils {
|
|
8
|
+
sdkType: SDKType;
|
|
8
9
|
disableProviderModal?: boolean | undefined;
|
|
9
10
|
localStorage: AsyncStorage;
|
|
10
11
|
sessionStorage: AsyncStorage;
|
|
@@ -14,7 +15,7 @@ export declare class ReactNativeUtils implements PlatformUtils {
|
|
|
14
15
|
p: string;
|
|
15
16
|
q: string;
|
|
16
17
|
}>;
|
|
17
|
-
keygen(ctx: Ctx, userId: string, type: Exclude<
|
|
18
|
+
keygen(ctx: Ctx, userId: string, type: Exclude<TWalletType, 'SOLANA'>, _secretKey: string | null, _sessionCookie: string, _emailProps?: BackupKitEmailProps | undefined): Promise<{
|
|
18
19
|
signer: string;
|
|
19
20
|
walletId: string;
|
|
20
21
|
}>;
|
|
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
7
7
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
|
-
import { KeyShareType
|
|
10
|
+
import { KeyShareType } from '@getpara/user-management-client';
|
|
11
11
|
import { NativeModules } from 'react-native';
|
|
12
12
|
import { AsyncStorage } from '../AsyncStorage.js';
|
|
13
13
|
import { KeychainStorage } from '../KeychainStorage.js';
|
|
@@ -47,6 +47,7 @@ function sendTransactionRequest(ctx, userId, walletId, protocolId, transaction,
|
|
|
47
47
|
}
|
|
48
48
|
export class ReactNativeUtils {
|
|
49
49
|
constructor() {
|
|
50
|
+
this.sdkType = 'REACT_NATIVE';
|
|
50
51
|
this.localStorage = new AsyncStorage();
|
|
51
52
|
this.sessionStorage = new AsyncStorage();
|
|
52
53
|
this.secureStorage = new KeychainStorage();
|
|
@@ -63,7 +64,7 @@ export class ReactNativeUtils {
|
|
|
63
64
|
const { walletId, protocolId } = yield ctx.client.createWallet(userId, {
|
|
64
65
|
type,
|
|
65
66
|
useTwoSigners: true,
|
|
66
|
-
scheme: ctx.useDKLS ?
|
|
67
|
+
scheme: ctx.useDKLS ? 'DKLS' : 'CGGMP',
|
|
67
68
|
});
|
|
68
69
|
if (ctx.mpcComputationClient && !ctx.useDKLS) {
|
|
69
70
|
const { signer } = yield keygenRequest(ctx, userId, walletId, protocolId);
|
|
@@ -141,8 +142,8 @@ export class ReactNativeUtils {
|
|
|
141
142
|
ed25519Keygen(ctx, userId, _sessionCookie, _emailProps) {
|
|
142
143
|
return __awaiter(this, void 0, void 0, function* () {
|
|
143
144
|
const { walletId, protocolId } = yield ctx.client.createWallet(userId, {
|
|
144
|
-
scheme:
|
|
145
|
-
type:
|
|
145
|
+
scheme: 'ED25519',
|
|
146
|
+
type: 'SOLANA',
|
|
146
147
|
});
|
|
147
148
|
const signer = yield ParaSignerModule.ed25519CreateAccount(walletId, protocolId);
|
|
148
149
|
return { signer, walletId };
|
|
@@ -153,8 +154,8 @@ export class ReactNativeUtils {
|
|
|
153
154
|
const { walletId, protocolId } = yield ctx.client.createPregenWallet({
|
|
154
155
|
pregenIdentifier,
|
|
155
156
|
pregenIdentifierType,
|
|
156
|
-
scheme:
|
|
157
|
-
type:
|
|
157
|
+
scheme: 'ED25519',
|
|
158
|
+
type: 'SOLANA',
|
|
158
159
|
});
|
|
159
160
|
const signer = yield ParaSignerModule.ed25519CreateAccount(walletId, protocolId);
|
|
160
161
|
return { signer, walletId };
|
|
@@ -162,7 +163,7 @@ export class ReactNativeUtils {
|
|
|
162
163
|
}
|
|
163
164
|
ed25519Sign(ctx, userId, walletId, share, base64Bytes, _sessionCookie) {
|
|
164
165
|
return __awaiter(this, void 0, void 0, function* () {
|
|
165
|
-
const { protocolId } = yield ctx.client.preSignMessage(userId, walletId, base64Bytes,
|
|
166
|
+
const { protocolId } = yield ctx.client.preSignMessage(userId, walletId, base64Bytes, 'ED25519');
|
|
166
167
|
const base64Sig = yield ParaSignerModule.ed25519Sign(protocolId, share, base64Bytes);
|
|
167
168
|
return { signature: base64Sig };
|
|
168
169
|
});
|
package/dist/shim.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Buffer } from '@craftzdog/react-native-buffer';
|
|
|
8
8
|
import process from 'process';
|
|
9
9
|
import 'react-native-url-polyfill/auto';
|
|
10
10
|
import { TextEncoder, TextDecoder } from 'text-encoding';
|
|
11
|
+
import structuredClone from '@ungap/structured-clone';
|
|
11
12
|
const setupProcessPolyfill = () => {
|
|
12
13
|
if (typeof globalThis.process === 'undefined') {
|
|
13
14
|
globalThis.process = process;
|
|
@@ -61,8 +62,14 @@ const setupTextEncodingPolyfills = () => {
|
|
|
61
62
|
globalThis.TextEncoder = TextEncoder;
|
|
62
63
|
globalThis.TextDecoder = TextDecoder;
|
|
63
64
|
};
|
|
65
|
+
const setupStructuredClonePolyfill = () => {
|
|
66
|
+
if (typeof globalThis.structuredClone === 'undefined') {
|
|
67
|
+
globalThis.structuredClone = structuredClone;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
64
70
|
setupProcessPolyfill();
|
|
65
71
|
setupBufferPolyfill();
|
|
66
72
|
setupBase64Polyfills();
|
|
67
73
|
setupCryptoPolyfills();
|
|
68
74
|
setupTextEncodingPolyfills();
|
|
75
|
+
setupStructuredClonePolyfill();
|
package/package.json
CHANGED
|
@@ -1,50 +1,56 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getpara/react-native-wallet",
|
|
3
|
-
"version": "2.0.0-alpha.3",
|
|
4
3
|
"description": "Para Wallet for React Native",
|
|
5
|
-
"
|
|
4
|
+
"version": "2.0.0-alpha.30",
|
|
6
5
|
"author": "Para Team <hello@getpara.com> (https://getpara.com)",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"module": "dist/index.js",
|
|
9
|
-
"types": "dist/index.d.ts",
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"src",
|
|
13
|
-
"ios",
|
|
14
|
-
"android",
|
|
15
|
-
"cpp",
|
|
16
|
-
"*.podspec",
|
|
17
|
-
"signer.xcframework",
|
|
18
|
-
"signer.aar"
|
|
19
|
-
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"build": "rm -rf dist && tsc",
|
|
22
|
-
"compile-signer": "bash ./scripts/compileSigner.sh"
|
|
23
|
-
},
|
|
24
6
|
"dependencies": {
|
|
25
|
-
"@getpara/core-sdk": "2.0.0-alpha.
|
|
26
|
-
"@getpara/user-management-client": "2.0.0-alpha.
|
|
27
|
-
"@getpara/web-sdk": "2.0.0-alpha.
|
|
7
|
+
"@getpara/core-sdk": "2.0.0-alpha.30",
|
|
8
|
+
"@getpara/user-management-client": "2.0.0-alpha.30",
|
|
9
|
+
"@getpara/web-sdk": "2.0.0-alpha.30",
|
|
28
10
|
"@peculiar/webcrypto": "^1.5.0",
|
|
29
|
-
"@
|
|
11
|
+
"@ungap/structured-clone": "1.3.0",
|
|
30
12
|
"node-forge": "1.3.1",
|
|
31
13
|
"react-native-url-polyfill": "2.0.0",
|
|
32
14
|
"text-encoding": "0.7.0"
|
|
33
15
|
},
|
|
34
16
|
"devDependencies": {
|
|
35
17
|
"@craftzdog/react-native-buffer": "6.0.5",
|
|
36
|
-
"@react-native-async-storage/async-storage": "2.1.
|
|
18
|
+
"@react-native-async-storage/async-storage": "2.1.2",
|
|
37
19
|
"@types/node-forge": "1.3.1",
|
|
38
20
|
"@types/react": "^18.0.31",
|
|
39
21
|
"@types/react-native": "0.70.0",
|
|
40
22
|
"@types/text-encoding": "0.0.39",
|
|
41
|
-
"react-native-keychain": "
|
|
23
|
+
"react-native-keychain": "10.0.0",
|
|
42
24
|
"react-native-modpow": "1.1.0",
|
|
43
|
-
"react-native-passkey": "3.
|
|
25
|
+
"react-native-passkey": "3.1.0",
|
|
44
26
|
"react-native-quick-base64": "2.1.2",
|
|
45
|
-
"react-native-quick-crypto": "0.7.
|
|
46
|
-
"typescript": "^5.
|
|
27
|
+
"react-native-quick-crypto": "0.7.12",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
47
29
|
},
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./shim": {
|
|
35
|
+
"default": "./dist/shim.js"
|
|
36
|
+
},
|
|
37
|
+
"./dist/shim.js": {
|
|
38
|
+
"default": "./dist/shim.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist",
|
|
43
|
+
"src",
|
|
44
|
+
"ios",
|
|
45
|
+
"android",
|
|
46
|
+
"cpp",
|
|
47
|
+
"*.podspec",
|
|
48
|
+
"signer.xcframework",
|
|
49
|
+
"signer.aar"
|
|
50
|
+
],
|
|
51
|
+
"homepage": "https://getpara.com",
|
|
52
|
+
"main": "./dist/index.js",
|
|
53
|
+
"module": "./dist/index.js",
|
|
48
54
|
"peerDependencies": {
|
|
49
55
|
"@craftzdog/react-native-buffer": "*",
|
|
50
56
|
"@react-native-async-storage/async-storage": "*",
|
|
@@ -60,5 +66,32 @@
|
|
|
60
66
|
"publishConfig": {
|
|
61
67
|
"access": "public"
|
|
62
68
|
},
|
|
63
|
-
"
|
|
69
|
+
"react-native": {
|
|
70
|
+
".": "./dist/index.js",
|
|
71
|
+
"./shim": "./dist/shim.js",
|
|
72
|
+
"./dist/shim.js": "./dist/shim.js"
|
|
73
|
+
},
|
|
74
|
+
"scripts": {
|
|
75
|
+
"build": "rm -rf dist && tsc",
|
|
76
|
+
"compile-signer": "bash ./scripts/compileSigner.sh",
|
|
77
|
+
"test": "vitest run --coverage"
|
|
78
|
+
},
|
|
79
|
+
"sideEffects": [
|
|
80
|
+
"./dist/shim.js"
|
|
81
|
+
],
|
|
82
|
+
"types": "./dist/index.d.ts",
|
|
83
|
+
"typesVersions": {
|
|
84
|
+
"*": {
|
|
85
|
+
"shim": [
|
|
86
|
+
"./dist/shim.d.ts"
|
|
87
|
+
],
|
|
88
|
+
"dist/shim.js": [
|
|
89
|
+
"./dist/shim.d.ts"
|
|
90
|
+
],
|
|
91
|
+
"*": [
|
|
92
|
+
"./dist/index.d.ts"
|
|
93
|
+
]
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"gitHead": "8b06219b9c248a3fbdbd05dc7501e8042c369301"
|
|
64
97
|
}
|
package/src/AsyncStorage.ts
CHANGED
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
import { StorageUtils } from '@getpara/web-sdk';
|
|
2
2
|
import RNAsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Implements `StorageUtils` using React Native Async Storage.
|
|
6
|
-
*/
|
|
7
4
|
export class AsyncStorage implements StorageUtils {
|
|
8
|
-
async
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
async get(key: string): Promise<string | null> {
|
|
6
|
+
try {
|
|
7
|
+
return await RNAsyncStorage.getItem(key);
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.warn('Error retrieving stored item:', error);
|
|
10
|
+
return null;
|
|
14
11
|
}
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
async
|
|
18
|
-
|
|
14
|
+
async set(key: string, value: string): Promise<void> {
|
|
15
|
+
try {
|
|
16
|
+
await RNAsyncStorage.setItem(key, value);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.warn(`Error storing key ${key}:`, error);
|
|
19
|
+
}
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
async removeItem(key: string): Promise<void> {
|
|
22
|
-
|
|
23
|
+
try {
|
|
24
|
+
await RNAsyncStorage.removeItem(key);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.warn(`Error removing key ${key}:`, error);
|
|
27
|
+
}
|
|
23
28
|
}
|
|
24
29
|
|
|
25
|
-
async
|
|
26
|
-
|
|
30
|
+
async clear(prefix: string): Promise<void> {
|
|
31
|
+
try {
|
|
32
|
+
const keys = await RNAsyncStorage.getAllKeys();
|
|
33
|
+
for (const key of keys) {
|
|
34
|
+
if (key.startsWith(prefix)) {
|
|
35
|
+
try {
|
|
36
|
+
await RNAsyncStorage.removeItem(key);
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.warn(`Error clearing key ${key}:`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn(`Error getting keys for prefix ${prefix}:`, error);
|
|
44
|
+
}
|
|
27
45
|
}
|
|
28
46
|
}
|
package/src/KeychainStorage.ts
CHANGED
|
@@ -2,21 +2,7 @@ import { StorageUtils } from '@getpara/web-sdk';
|
|
|
2
2
|
import Keychain from 'react-native-keychain';
|
|
3
3
|
|
|
4
4
|
const USERNAME = '@CAPSULE';
|
|
5
|
-
const KEYCHAIN_USER_CANCELLED_ERRORS = [
|
|
6
|
-
'user canceled the operation',
|
|
7
|
-
'error: code: 13, msg: cancel',
|
|
8
|
-
'error: code: 10, msg: fingerprint operation canceled by the user',
|
|
9
|
-
];
|
|
10
5
|
|
|
11
|
-
function isUserCancelledError(error: Error) {
|
|
12
|
-
return KEYCHAIN_USER_CANCELLED_ERRORS.some(userCancelledError =>
|
|
13
|
-
error.toString().toLowerCase().includes(userCancelledError),
|
|
14
|
-
);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Implements `StorageUtils` using React Native `Keychain`.
|
|
19
|
-
*/
|
|
20
6
|
export class KeychainStorage implements StorageUtils {
|
|
21
7
|
async get(key: string): Promise<string | null> {
|
|
22
8
|
try {
|
|
@@ -28,32 +14,49 @@ export class KeychainStorage implements StorageUtils {
|
|
|
28
14
|
}
|
|
29
15
|
return item.password;
|
|
30
16
|
} catch (error) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
throw new Error('Error retrieving stored item ' + error.message);
|
|
34
|
-
}
|
|
35
|
-
throw error;
|
|
17
|
+
console.warn('Error retrieving stored item:', error);
|
|
18
|
+
return null;
|
|
36
19
|
}
|
|
37
20
|
}
|
|
21
|
+
|
|
38
22
|
async set(key: string, value: string): Promise<void> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
try {
|
|
24
|
+
const result = await Keychain.setGenericPassword(USERNAME, value, {
|
|
25
|
+
service: key,
|
|
26
|
+
accessible: Keychain.ACCESSIBLE.WHEN_UNLOCKED,
|
|
27
|
+
securityLevel: Keychain.SECURITY_LEVEL.ANY,
|
|
28
|
+
storage: Keychain.STORAGE_TYPE.AES_GCM_NO_AUTH,
|
|
29
|
+
});
|
|
30
|
+
if (!result) {
|
|
31
|
+
console.warn(`Failed to store key ${key}`);
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.warn(`Error storing key ${key}:`, error);
|
|
46
35
|
}
|
|
47
36
|
}
|
|
37
|
+
|
|
48
38
|
async removeItem(key: string): Promise<void> {
|
|
49
|
-
|
|
39
|
+
try {
|
|
40
|
+
await Keychain.resetGenericPassword({ service: key });
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.warn(`Error removing key ${key}:`, error);
|
|
43
|
+
}
|
|
50
44
|
}
|
|
45
|
+
|
|
51
46
|
async clear(prefix: string): Promise<void> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
try {
|
|
48
|
+
const services = await Keychain.getAllGenericPasswordServices();
|
|
49
|
+
for (const key of services) {
|
|
50
|
+
if (key && key.startsWith(prefix)) {
|
|
51
|
+
try {
|
|
52
|
+
await Keychain.resetGenericPassword({ service: key });
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.warn(`Error clearing key ${key}:`, error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
56
57
|
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.warn(`Error getting services for prefix ${prefix}:`, error);
|
|
57
60
|
}
|
|
58
61
|
}
|
|
59
62
|
}
|
package/src/config.ts
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
getSHA256HashHex,
|
|
14
14
|
parseCredentialCreationRes,
|
|
15
15
|
} from '@getpara/web-sdk';
|
|
16
|
-
import * as Sentry from '@sentry/react-native';
|
|
17
16
|
|
|
18
17
|
import { ReactNativeUtils } from './ReactNativeUtils.js';
|
|
19
18
|
import {
|
|
@@ -23,7 +22,7 @@ import {
|
|
|
23
22
|
PasskeyGetRequest,
|
|
24
23
|
PasskeyGetResult,
|
|
25
24
|
} from 'react-native-passkey';
|
|
26
|
-
import { PublicKeyStatus,
|
|
25
|
+
import { CurrentWalletIds, PublicKeyStatus, TWalletScheme } from '@getpara/user-management-client';
|
|
27
26
|
import { setEnv } from '../config.js';
|
|
28
27
|
import base64url from 'base64url';
|
|
29
28
|
import { webcrypto } from 'crypto';
|
|
@@ -52,15 +51,6 @@ export class ParaMobile extends ParaCore {
|
|
|
52
51
|
constructor(env: Environment, apiKey: string, relyingPartyId?: string, opts?: ConstructorOpts) {
|
|
53
52
|
super(env, apiKey, opts);
|
|
54
53
|
|
|
55
|
-
// starting with non-prod to see what kind of errors we get and if sensitive data is tracked
|
|
56
|
-
// will turn on in prod after monitoring
|
|
57
|
-
if (env !== Environment.PROD && env !== Environment.DEV) {
|
|
58
|
-
Sentry.init({
|
|
59
|
-
environment: env.toLowerCase(),
|
|
60
|
-
dsn: 'https://59cea0cfbbb30a646c4e9f2feea06da4@o4504568036720640.ingest.us.sentry.io/4508850922323968',
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
|
|
64
54
|
setEnv(env);
|
|
65
55
|
|
|
66
56
|
if (relyingPartyId) {
|
|
@@ -82,10 +72,18 @@ export class ParaMobile extends ParaCore {
|
|
|
82
72
|
}
|
|
83
73
|
}
|
|
84
74
|
|
|
75
|
+
protected async ready() {
|
|
76
|
+
this.isReady = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
85
79
|
protected getPlatformUtils(): PlatformUtils {
|
|
86
80
|
return new ReactNativeUtils();
|
|
87
81
|
}
|
|
88
82
|
|
|
83
|
+
async isPasskeySupported(): Promise<boolean> {
|
|
84
|
+
return Passkey.isSupported();
|
|
85
|
+
}
|
|
86
|
+
|
|
89
87
|
/**
|
|
90
88
|
* Registers a passkey for the user.
|
|
91
89
|
* @param {Auth<'email'> | Auth<'phone'>} auth - The user's authentication details
|
|
@@ -172,7 +170,7 @@ export class ParaMobile extends ParaCore {
|
|
|
172
170
|
* @param {AuthParams} params - The authentication parameters.
|
|
173
171
|
* @returns {Promise<void>}
|
|
174
172
|
*/
|
|
175
|
-
async
|
|
173
|
+
async loginWithPasskey(): Promise<void> {
|
|
176
174
|
this.assertIsAuthSet();
|
|
177
175
|
const userId = this.assertUserId();
|
|
178
176
|
|
|
@@ -195,7 +193,7 @@ export class ParaMobile extends ParaCore {
|
|
|
195
193
|
resultJson = result;
|
|
196
194
|
}
|
|
197
195
|
|
|
198
|
-
const { partnerId } = await this.ctx.client.touchSession();
|
|
196
|
+
const { partnerId, sessionLookupId } = await this.ctx.client.touchSession();
|
|
199
197
|
const publicKey = resultJson.id;
|
|
200
198
|
const verifyWebChallengeResult = await this.ctx.client.verifyWebChallenge(partnerId, {
|
|
201
199
|
publicKey,
|
|
@@ -206,7 +204,7 @@ export class ParaMobile extends ParaCore {
|
|
|
206
204
|
},
|
|
207
205
|
});
|
|
208
206
|
|
|
209
|
-
if (userId !== verifyWebChallengeResult.userId) {
|
|
207
|
+
if (userId !== verifyWebChallengeResult.data.userId) {
|
|
210
208
|
throw new Error('User ID mismatch');
|
|
211
209
|
}
|
|
212
210
|
|
|
@@ -234,7 +232,7 @@ export class ParaMobile extends ParaCore {
|
|
|
234
232
|
decryptedShares = await decryptPrivateKeyAndDecryptShare(
|
|
235
233
|
resultJson.response.userHandle,
|
|
236
234
|
encryptedSharesResult.data.keyShares,
|
|
237
|
-
encryptedPrivateKeys[0]
|
|
235
|
+
encryptedPrivateKeys[0]!.encryptedPrivateKey,
|
|
238
236
|
);
|
|
239
237
|
}
|
|
240
238
|
|
|
@@ -249,11 +247,21 @@ export class ParaMobile extends ParaCore {
|
|
|
249
247
|
signer: decryptedShare.signer,
|
|
250
248
|
address: desiredWallet.address || undefined,
|
|
251
249
|
publicKey: desiredWallet.publicKey || undefined,
|
|
252
|
-
scheme: desiredWallet.scheme as
|
|
250
|
+
scheme: desiredWallet.scheme as TWalletScheme,
|
|
253
251
|
type: desiredWallet.type || undefined,
|
|
254
252
|
};
|
|
255
253
|
}
|
|
256
254
|
|
|
255
|
+
const currentWalletIds: CurrentWalletIds = {};
|
|
256
|
+
for (const wallet of Object.values(walletsToInsert)) {
|
|
257
|
+
const { id, type } = wallet;
|
|
258
|
+
const currentIdsForType = currentWalletIds[type || 'EVM'] || [];
|
|
259
|
+
currentWalletIds[type || 'EVM'] = [...currentIdsForType, id];
|
|
260
|
+
}
|
|
261
|
+
|
|
257
262
|
await this.setWallets(walletsToInsert);
|
|
263
|
+
await this.setCurrentWalletIds(currentWalletIds, {
|
|
264
|
+
sessionLookupId,
|
|
265
|
+
});
|
|
258
266
|
}
|
|
259
267
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PlatformUtils, TPregenIdentifierType } from '@getpara/web-sdk';
|
|
2
2
|
import { Ctx } from '@getpara/web-sdk';
|
|
3
3
|
import { SignatureRes } from '@getpara/web-sdk';
|
|
4
|
-
import { BackupKitEmailProps, KeyShareType,
|
|
4
|
+
import { BackupKitEmailProps, KeyShareType, TWalletType, SDKType } from '@getpara/user-management-client';
|
|
5
5
|
import { NativeModules } from 'react-native';
|
|
6
6
|
|
|
7
7
|
import { AsyncStorage } from '../AsyncStorage.js';
|
|
@@ -55,6 +55,7 @@ async function sendTransactionRequest(
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export class ReactNativeUtils implements PlatformUtils {
|
|
58
|
+
sdkType: SDKType = 'REACT_NATIVE';
|
|
58
59
|
disableProviderModal?: boolean | undefined;
|
|
59
60
|
localStorage = new AsyncStorage();
|
|
60
61
|
sessionStorage = new AsyncStorage();
|
|
@@ -69,7 +70,7 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
69
70
|
async keygen(
|
|
70
71
|
ctx: Ctx,
|
|
71
72
|
userId: string,
|
|
72
|
-
type: Exclude<
|
|
73
|
+
type: Exclude<TWalletType, 'SOLANA'>,
|
|
73
74
|
_secretKey: string | null,
|
|
74
75
|
_sessionCookie: string,
|
|
75
76
|
_emailProps?: BackupKitEmailProps | undefined,
|
|
@@ -77,7 +78,7 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
77
78
|
const { walletId, protocolId } = await ctx.client.createWallet(userId, {
|
|
78
79
|
type,
|
|
79
80
|
useTwoSigners: true,
|
|
80
|
-
scheme: ctx.useDKLS ?
|
|
81
|
+
scheme: ctx.useDKLS ? 'DKLS' : 'CGGMP',
|
|
81
82
|
});
|
|
82
83
|
|
|
83
84
|
if (ctx.mpcComputationClient && !ctx.useDKLS) {
|
|
@@ -220,8 +221,8 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
220
221
|
walletId: string;
|
|
221
222
|
}> {
|
|
222
223
|
const { walletId, protocolId } = await ctx.client.createWallet(userId, {
|
|
223
|
-
scheme:
|
|
224
|
-
type:
|
|
224
|
+
scheme: 'ED25519',
|
|
225
|
+
type: 'SOLANA',
|
|
225
226
|
});
|
|
226
227
|
|
|
227
228
|
const signer = await ParaSignerModule.ed25519CreateAccount(walletId, protocolId);
|
|
@@ -240,8 +241,8 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
240
241
|
const { walletId, protocolId } = await ctx.client.createPregenWallet({
|
|
241
242
|
pregenIdentifier,
|
|
242
243
|
pregenIdentifierType,
|
|
243
|
-
scheme:
|
|
244
|
-
type:
|
|
244
|
+
scheme: 'ED25519',
|
|
245
|
+
type: 'SOLANA',
|
|
245
246
|
});
|
|
246
247
|
|
|
247
248
|
const signer = await ParaSignerModule.ed25519CreateAccount(walletId, protocolId);
|
|
@@ -256,7 +257,7 @@ export class ReactNativeUtils implements PlatformUtils {
|
|
|
256
257
|
base64Bytes: string,
|
|
257
258
|
_sessionCookie: string,
|
|
258
259
|
): Promise<SignatureRes> {
|
|
259
|
-
const { protocolId } = await ctx.client.preSignMessage(userId, walletId, base64Bytes,
|
|
260
|
+
const { protocolId } = await ctx.client.preSignMessage(userId, walletId, base64Bytes, 'ED25519');
|
|
260
261
|
|
|
261
262
|
const base64Sig = await ParaSignerModule.ed25519Sign(protocolId, share, base64Bytes);
|
|
262
263
|
return { signature: base64Sig };
|
package/src/shim.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Buffer } from '@craftzdog/react-native-buffer';
|
|
|
8
8
|
import process from 'process';
|
|
9
9
|
import 'react-native-url-polyfill/auto';
|
|
10
10
|
import { TextEncoder, TextDecoder } from 'text-encoding';
|
|
11
|
+
import structuredClone from '@ungap/structured-clone';
|
|
11
12
|
|
|
12
13
|
const setupProcessPolyfill = () => {
|
|
13
14
|
if (typeof globalThis.process === 'undefined') {
|
|
@@ -67,8 +68,15 @@ const setupTextEncodingPolyfills = () => {
|
|
|
67
68
|
globalThis.TextDecoder = TextDecoder;
|
|
68
69
|
};
|
|
69
70
|
|
|
71
|
+
const setupStructuredClonePolyfill = () => {
|
|
72
|
+
if (typeof globalThis.structuredClone === 'undefined') {
|
|
73
|
+
globalThis.structuredClone = structuredClone;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
70
77
|
setupProcessPolyfill();
|
|
71
78
|
setupBufferPolyfill();
|
|
72
79
|
setupBase64Polyfills();
|
|
73
80
|
setupCryptoPolyfills();
|
|
74
81
|
setupTextEncodingPolyfills();
|
|
82
|
+
setupStructuredClonePolyfill();
|
|
File without changes
|