@getpara/react-native-wallet 2.0.0-alpha.3 → 2.0.0-alpha.31

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.
@@ -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
  }
@@ -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
- clear(prefix) {
12
+ get(key) {
16
13
  return __awaiter(this, void 0, void 0, function* () {
17
- const keys = yield RNAsyncStorage.getAllKeys();
18
- for (const key of keys) {
19
- if (key.startsWith(prefix)) {
20
- yield RNAsyncStorage.removeItem(key);
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
- get(key) {
23
+ set(key, value) {
26
24
  return __awaiter(this, void 0, void 0, function* () {
27
- return RNAsyncStorage.getItem(key);
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
- yield RNAsyncStorage.removeItem(key);
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
- set(key, value) {
43
+ clear(prefix) {
36
44
  return __awaiter(this, void 0, void 0, function* () {
37
- yield RNAsyncStorage.setItem(key, value);
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>;
@@ -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
- if (error instanceof Error && !isUserCancelledError(error)) {
37
- // triggered when biometry verification fails and user cancels the action
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
- const result = yield Keychain.setGenericPassword(USERNAME, value, {
47
- service: key,
48
- accessible: Keychain.ACCESSIBLE.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
49
- securityLevel: Keychain.SECURITY_LEVEL.ANY,
50
- });
51
- if (!result) {
52
- throw new Error('Failed to store key ' + key);
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
- yield Keychain.resetGenericPassword({ service: key });
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
- const services = yield Keychain.getAllGenericPasswordServices();
64
- for (const key of services) {
65
- if (key && key.startsWith(prefix)) {
66
- yield Keychain.resetGenericPassword({ service: key });
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
@@ -58,3 +58,4 @@ function init() {
58
58
  ParaSignerModule.setWsServerUrl(mpcNetworkWSServer);
59
59
  }
60
60
  init();
61
+ export { getBaseUrl, getPortalBaseURL };
@@ -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
- login(): Promise<void>;
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
- login() {
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, WalletType } from '@getpara/user-management-client';
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<WalletType, WalletType.SOLANA>, _secretKey: string | null, _sessionCookie: string, _emailProps?: BackupKitEmailProps | undefined): Promise<{
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, WalletScheme, WalletType } from '@getpara/user-management-client';
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 ? WalletScheme.DKLS : WalletScheme.CGGMP,
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: WalletScheme.ED25519,
145
- type: WalletType.SOLANA,
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: WalletScheme.ED25519,
157
- type: WalletType.SOLANA,
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, WalletScheme.ED25519);
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
- "homepage": "https://getpara.com",
4
+ "version": "2.0.0-alpha.31",
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.3",
26
- "@getpara/user-management-client": "2.0.0-alpha.3",
27
- "@getpara/web-sdk": "2.0.0-alpha.3",
7
+ "@getpara/core-sdk": "2.0.0-alpha.31",
8
+ "@getpara/user-management-client": "2.0.0-alpha.31",
9
+ "@getpara/web-sdk": "2.0.0-alpha.31",
28
10
  "@peculiar/webcrypto": "^1.5.0",
29
- "@sentry/react-native": "^6.7.0",
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.0",
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": "9.2.2",
23
+ "react-native-keychain": "10.0.0",
42
24
  "react-native-modpow": "1.1.0",
43
- "react-native-passkey": "3.0.0",
25
+ "react-native-passkey": "3.1.0",
44
26
  "react-native-quick-base64": "2.1.2",
45
- "react-native-quick-crypto": "0.7.11",
46
- "typescript": "^5.4.3"
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
- "gitHead": "77a1e04b06258842ca9c81e3db2a2b0092517659"
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": "54aac22b2d0b4cc730ab7f2e82cdd8a96729b039"
64
97
  }
@@ -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 clear(prefix: string): Promise<void> {
9
- const keys = await RNAsyncStorage.getAllKeys();
10
- for (const key of keys) {
11
- if (key.startsWith(prefix)) {
12
- await RNAsyncStorage.removeItem(key);
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 get(key: string): Promise<string | null> {
18
- return RNAsyncStorage.getItem(key);
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
- await RNAsyncStorage.removeItem(key);
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 set(key: string, value: string): Promise<void> {
26
- await RNAsyncStorage.setItem(key, value);
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
  }
@@ -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
- if (error instanceof Error && !isUserCancelledError(error)) {
32
- // triggered when biometry verification fails and user cancels the action
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
- const result = await Keychain.setGenericPassword(USERNAME, value, {
40
- service: key,
41
- accessible: Keychain.ACCESSIBLE.AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY,
42
- securityLevel: Keychain.SECURITY_LEVEL.ANY,
43
- });
44
- if (!result) {
45
- throw new Error('Failed to store key ' + key);
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
- await Keychain.resetGenericPassword({ service: key });
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
- const services = await Keychain.getAllGenericPasswordServices();
53
- for (const key of services) {
54
- if (key && key.startsWith(prefix)) {
55
- await Keychain.resetGenericPassword({ service: key });
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
@@ -66,3 +66,5 @@ function init() {
66
66
  }
67
67
 
68
68
  init();
69
+
70
+ export { getBaseUrl, getPortalBaseURL };
@@ -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, WalletScheme } from '@getpara/user-management-client';
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 login(): Promise<void> {
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].encryptedPrivateKey,
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 WalletScheme,
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, WalletScheme, WalletType } from '@getpara/user-management-client';
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<WalletType, WalletType.SOLANA>,
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 ? WalletScheme.DKLS : WalletScheme.CGGMP,
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: WalletScheme.ED25519,
224
- type: WalletType.SOLANA,
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: WalletScheme.ED25519,
244
- type: WalletType.SOLANA,
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, WalletScheme.ED25519);
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