toss-expo-sdk 0.1.0

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.
Files changed (116) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +292 -0
  3. package/lib/module/ble.js +103 -0
  4. package/lib/module/ble.js.map +1 -0
  5. package/lib/module/client/TossClient.js +324 -0
  6. package/lib/module/client/TossClient.js.map +1 -0
  7. package/lib/module/client/index.js +4 -0
  8. package/lib/module/client/index.js.map +1 -0
  9. package/lib/module/contexts/WalletContext.js +99 -0
  10. package/lib/module/contexts/WalletContext.js.map +1 -0
  11. package/lib/module/discovery.js +434 -0
  12. package/lib/module/discovery.js.map +1 -0
  13. package/lib/module/errors.js +47 -0
  14. package/lib/module/errors.js.map +1 -0
  15. package/lib/module/examples/offlinePaymentFlow.js +234 -0
  16. package/lib/module/examples/offlinePaymentFlow.js.map +1 -0
  17. package/lib/module/index.js +32 -0
  18. package/lib/module/index.js.map +1 -0
  19. package/lib/module/intent.js +223 -0
  20. package/lib/module/intent.js.map +1 -0
  21. package/lib/module/intentManager.js +145 -0
  22. package/lib/module/intentManager.js.map +1 -0
  23. package/lib/module/internal/arciumHelper.js +50 -0
  24. package/lib/module/internal/arciumHelper.js.map +1 -0
  25. package/lib/module/nfc.js +54 -0
  26. package/lib/module/nfc.js.map +1 -0
  27. package/lib/module/noise.js +14 -0
  28. package/lib/module/noise.js.map +1 -0
  29. package/lib/module/package.json +1 -0
  30. package/lib/module/qr.js +57 -0
  31. package/lib/module/qr.js.map +1 -0
  32. package/lib/module/reconciliation.js +329 -0
  33. package/lib/module/reconciliation.js.map +1 -0
  34. package/lib/module/services/authService.js +205 -0
  35. package/lib/module/services/authService.js.map +1 -0
  36. package/lib/module/storage/secureStorage.js +89 -0
  37. package/lib/module/storage/secureStorage.js.map +1 -0
  38. package/lib/module/storage.js +16 -0
  39. package/lib/module/storage.js.map +1 -0
  40. package/lib/module/sync.js +64 -0
  41. package/lib/module/sync.js.map +1 -0
  42. package/lib/module/types/tossUser.js +41 -0
  43. package/lib/module/types/tossUser.js.map +1 -0
  44. package/lib/module/utils/nonceUtils.js +38 -0
  45. package/lib/module/utils/nonceUtils.js.map +1 -0
  46. package/lib/typescript/package.json +1 -0
  47. package/lib/typescript/src/__tests__/index.test.d.ts +1 -0
  48. package/lib/typescript/src/__tests__/index.test.d.ts.map +1 -0
  49. package/lib/typescript/src/__tests__/reconciliation.test.d.ts +6 -0
  50. package/lib/typescript/src/__tests__/reconciliation.test.d.ts.map +1 -0
  51. package/lib/typescript/src/ble.d.ts +10 -0
  52. package/lib/typescript/src/ble.d.ts.map +1 -0
  53. package/lib/typescript/src/client/TossClient.d.ts +110 -0
  54. package/lib/typescript/src/client/TossClient.d.ts.map +1 -0
  55. package/lib/typescript/src/client/index.d.ts +3 -0
  56. package/lib/typescript/src/client/index.d.ts.map +1 -0
  57. package/lib/typescript/src/contexts/WalletContext.d.ts +20 -0
  58. package/lib/typescript/src/contexts/WalletContext.d.ts.map +1 -0
  59. package/lib/typescript/src/discovery.d.ts +188 -0
  60. package/lib/typescript/src/discovery.d.ts.map +1 -0
  61. package/lib/typescript/src/errors.d.ts +27 -0
  62. package/lib/typescript/src/errors.d.ts.map +1 -0
  63. package/lib/typescript/src/examples/offlinePaymentFlow.d.ts +48 -0
  64. package/lib/typescript/src/examples/offlinePaymentFlow.d.ts.map +1 -0
  65. package/lib/typescript/src/index.d.ts +13 -0
  66. package/lib/typescript/src/index.d.ts.map +1 -0
  67. package/lib/typescript/src/intent.d.ts +84 -0
  68. package/lib/typescript/src/intent.d.ts.map +1 -0
  69. package/lib/typescript/src/intentManager.d.ts +46 -0
  70. package/lib/typescript/src/intentManager.d.ts.map +1 -0
  71. package/lib/typescript/src/internal/arciumHelper.d.ts +19 -0
  72. package/lib/typescript/src/internal/arciumHelper.d.ts.map +1 -0
  73. package/lib/typescript/src/nfc.d.ts +7 -0
  74. package/lib/typescript/src/nfc.d.ts.map +1 -0
  75. package/lib/typescript/src/noise.d.ts +5 -0
  76. package/lib/typescript/src/noise.d.ts.map +1 -0
  77. package/lib/typescript/src/qr.d.ts +6 -0
  78. package/lib/typescript/src/qr.d.ts.map +1 -0
  79. package/lib/typescript/src/reconciliation.d.ts +65 -0
  80. package/lib/typescript/src/reconciliation.d.ts.map +1 -0
  81. package/lib/typescript/src/services/authService.d.ts +55 -0
  82. package/lib/typescript/src/services/authService.d.ts.map +1 -0
  83. package/lib/typescript/src/storage/secureStorage.d.ts +7 -0
  84. package/lib/typescript/src/storage/secureStorage.d.ts.map +1 -0
  85. package/lib/typescript/src/storage.d.ts +4 -0
  86. package/lib/typescript/src/storage.d.ts.map +1 -0
  87. package/lib/typescript/src/sync.d.ts +40 -0
  88. package/lib/typescript/src/sync.d.ts.map +1 -0
  89. package/lib/typescript/src/types/tossUser.d.ts +39 -0
  90. package/lib/typescript/src/types/tossUser.d.ts.map +1 -0
  91. package/lib/typescript/src/utils/nonceUtils.d.ts +8 -0
  92. package/lib/typescript/src/utils/nonceUtils.d.ts.map +1 -0
  93. package/package.json +176 -0
  94. package/src/__tests__/index.test.tsx +1 -0
  95. package/src/__tests__/reconciliation.test.tsx +361 -0
  96. package/src/ble.ts +138 -0
  97. package/src/client/TossClient.ts +435 -0
  98. package/src/client/index.ts +2 -0
  99. package/src/contexts/WalletContext.tsx +127 -0
  100. package/src/discovery.ts +542 -0
  101. package/src/errors.ts +51 -0
  102. package/src/examples/offlinePaymentFlow.ts +331 -0
  103. package/src/index.tsx +61 -0
  104. package/src/intent.ts +328 -0
  105. package/src/intentManager.ts +164 -0
  106. package/src/internal/arciumHelper.ts +58 -0
  107. package/src/nfc.ts +57 -0
  108. package/src/noise.ts +9 -0
  109. package/src/qr.tsx +65 -0
  110. package/src/reconciliation.ts +421 -0
  111. package/src/services/authService.ts +238 -0
  112. package/src/storage/secureStorage.ts +100 -0
  113. package/src/storage.ts +17 -0
  114. package/src/sync.ts +101 -0
  115. package/src/types/tossUser.ts +81 -0
  116. package/src/utils/nonceUtils.ts +56 -0
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+
3
+ import * as SecureStore from 'expo-secure-store';
4
+ import { Keypair, PublicKey } from '@solana/web3.js';
5
+ import * as LocalAuthentication from 'expo-local-authentication';
6
+ import crypto from 'crypto';
7
+ export const SESSION_KEY = 'toss_user_session';
8
+ const WALLET_KEY = 'toss_encrypted_wallet';
9
+ const BIOMETRIC_SALT_KEY = 'toss_biometric_salt';
10
+ export class AuthService {
11
+ static async signInWithWallet(walletAddress, isTemporary = false) {
12
+ // In a real implementation, this would call your backend
13
+ const session = {
14
+ id: `sess_${Date.now()}`,
15
+ token: `token_${Math.random().toString(36).substr(2, 9)}`,
16
+ expiresAt: isTemporary ? Date.now() + 1000 * 60 * 60 * 24 // 24 hours for temporary
17
+ : Date.now() + 1000 * 60 * 60 * 24 * 30,
18
+ // 30 days
19
+ walletAddress
20
+ };
21
+ const user = {
22
+ userId: `user_${walletAddress.slice(0, 8)}`,
23
+ username: `user_${walletAddress.slice(0, 6)}`,
24
+ wallet: {
25
+ publicKey: new PublicKey(walletAddress),
26
+ isVerified: false,
27
+ createdAt: new Date().toISOString()
28
+ },
29
+ device: {
30
+ id: 'device_id_here',
31
+ // You'd get this from the device
32
+ lastActive: new Date().toISOString(),
33
+ client: 'mobile'
34
+ },
35
+ status: 'active',
36
+ lastSeen: new Date().toISOString(),
37
+ tossFeatures: {
38
+ canSend: true,
39
+ canReceive: true,
40
+ isPrivateTxEnabled: true,
41
+ maxTransactionAmount: 10000
42
+ },
43
+ createdAt: new Date().toISOString(),
44
+ updatedAt: new Date().toISOString()
45
+ };
46
+ await this.saveSession(session);
47
+ return {
48
+ user,
49
+ session
50
+ };
51
+ }
52
+ static async saveSession(session) {
53
+ await SecureStore.setItemAsync(SESSION_KEY, JSON.stringify(session));
54
+ }
55
+ static async getSession() {
56
+ const session = await SecureStore.getItemAsync(SESSION_KEY);
57
+ return session ? JSON.parse(session) : null;
58
+ }
59
+ static async signOut() {
60
+ await SecureStore.deleteItemAsync(SESSION_KEY);
61
+ await SecureStore.deleteItemAsync(WALLET_KEY);
62
+ }
63
+ static async isWalletUnlocked() {
64
+ const isAvailable = await SecureStore.isAvailableAsync();
65
+ if (!isAvailable) return false;
66
+ const item = await SecureStore.getItemAsync(WALLET_KEY);
67
+ return item !== null;
68
+ }
69
+ static async unlockWalletWithBiometrics() {
70
+ const hasHardware = await LocalAuthentication.hasHardwareAsync();
71
+ const isEnrolled = await LocalAuthentication.isEnrolledAsync();
72
+ if (!hasHardware || !isEnrolled) {
73
+ throw new Error('Biometric authentication required but not available on this device');
74
+ }
75
+
76
+ // REQUIRED: Biometric authentication before key access
77
+ const result = await LocalAuthentication.authenticateAsync({
78
+ promptMessage: 'Biometric authentication required to access wallet',
79
+ fallbackLabel: 'Enter PIN',
80
+ disableDeviceFallback: false
81
+ });
82
+ if (!result.success) {
83
+ throw new Error('Biometric authentication failed - access denied');
84
+ }
85
+
86
+ // Only after successful biometric: retrieve encrypted keypair
87
+ const encrypted = await SecureStore.getItemAsync(WALLET_KEY);
88
+ if (!encrypted) {
89
+ throw new Error('Wallet not found - ensure wallet is set up first');
90
+ }
91
+ const salt = await SecureStore.getItemAsync(BIOMETRIC_SALT_KEY);
92
+ if (!salt) {
93
+ throw new Error('Wallet configuration corrupted');
94
+ }
95
+ try {
96
+ const decryptedData = JSON.parse(encrypted);
97
+ if (!decryptedData.publicKey || !decryptedData.secretKey) {
98
+ throw new Error('Invalid wallet data');
99
+ }
100
+
101
+ // Reconstruct keypair from encrypted storage
102
+ const secretKeyArray = new Uint8Array(decryptedData.secretKey);
103
+ const keypair = Keypair.fromSecretKey(secretKeyArray);
104
+
105
+ // Verify keypair integrity
106
+ if (keypair.publicKey.toString() !== decryptedData.publicKey) {
107
+ throw new Error('Keypair verification failed - wallet may be corrupted');
108
+ }
109
+
110
+ // Keypair returned but never exported/stored externally
111
+ return keypair;
112
+ } catch (error) {
113
+ throw new Error(`Failed to unlock wallet: ${error instanceof Error ? error.message : String(error)}`);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Setup biometric-protected wallet (REQUIRED for security)
119
+ *
120
+ * SECURITY CRITICAL:
121
+ * - Private keypair is encrypted and stored in hardware-secure storage
122
+ * - Private key NEVER accessible without biometric authentication
123
+ * - User CANNOT export, backup, or access seed phrase
124
+ * - Keypair is device-specific and non-custodial
125
+ *
126
+ * @param keypair User's Solana keypair (never re-used or exported)
127
+ * @param useBiometrics Must be true (biometric is mandatory, not optional)
128
+ */
129
+ static async setupWalletProtection(keypair, useBiometrics = true) {
130
+ if (!useBiometrics) {
131
+ throw new Error('❌ SECURITY ERROR: Biometric protection is mandatory for wallet security');
132
+ }
133
+
134
+ // Verify biometric is available on device
135
+ const hasHardware = await LocalAuthentication.hasHardwareAsync();
136
+ const isEnrolled = await LocalAuthentication.isEnrolledAsync();
137
+ if (!hasHardware || !isEnrolled) {
138
+ throw new Error('❌ Biometric authentication required but not configured on device');
139
+ }
140
+
141
+ // Generate unique salt for this wallet
142
+ const salt = crypto.getRandomValues(new Uint8Array(16)).toString();
143
+ await SecureStore.setItemAsync(BIOMETRIC_SALT_KEY, salt);
144
+
145
+ // Encrypt and store keypair in hardware-backed secure storage
146
+ const walletData = {
147
+ publicKey: keypair.publicKey.toString(),
148
+ secretKey: Array.from(keypair.secretKey),
149
+ // Serializable format only
150
+ createdAt: Date.now(),
151
+ biometricRequired: true,
152
+ nonCustodial: true,
153
+ deviceSpecific: true,
154
+ exportable: false // Explicitly non-exportable
155
+ };
156
+
157
+ // Store in Secure Enclave (iOS) or Keymaster (Android)
158
+ await SecureStore.setItemAsync(WALLET_KEY, JSON.stringify(walletData));
159
+ }
160
+
161
+ /**
162
+ * Verify wallet is stored securely (requires biometric to access)
163
+ * @returns true if wallet exists and requires biometric
164
+ */
165
+ static async isKeypairStoredSecurely() {
166
+ const stored = await SecureStore.getItemAsync(WALLET_KEY);
167
+ return stored !== null;
168
+ }
169
+
170
+ /**
171
+ * Get public key only (NO AUTHENTICATION REQUIRED - public key is safe)
172
+ * Use this for displaying wallet address, sending funds to, etc.
173
+ */
174
+ static async getPublicKeyWithoutAuth() {
175
+ try {
176
+ const encrypted = await SecureStore.getItemAsync(WALLET_KEY);
177
+ if (!encrypted) return null;
178
+ const data = JSON.parse(encrypted);
179
+ return new PublicKey(data.publicKey);
180
+ } catch (error) {
181
+ console.error('Failed to get public key:', error);
182
+ return null;
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Lock wallet from memory (does NOT delete stored keypair)
188
+ * Keypair remains encrypted in secure storage
189
+ */
190
+ static async lockWalletFromMemory() {
191
+ // This is handled by WalletContext clearing the keypair state
192
+ // The encrypted keypair stays in SecureStore
193
+ }
194
+
195
+ /**
196
+ * Permanently delete wallet (IRREVERSIBLE)
197
+ * Only use for logout or account deletion
198
+ */
199
+ static async deleteWalletPermanently() {
200
+ await SecureStore.deleteItemAsync(WALLET_KEY);
201
+ await SecureStore.deleteItemAsync(BIOMETRIC_SALT_KEY);
202
+ await SecureStore.deleteItemAsync(SESSION_KEY);
203
+ }
204
+ }
205
+ //# sourceMappingURL=authService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SecureStore","Keypair","PublicKey","LocalAuthentication","crypto","SESSION_KEY","WALLET_KEY","BIOMETRIC_SALT_KEY","AuthService","signInWithWallet","walletAddress","isTemporary","session","id","Date","now","token","Math","random","toString","substr","expiresAt","user","userId","slice","username","wallet","publicKey","isVerified","createdAt","toISOString","device","lastActive","client","status","lastSeen","tossFeatures","canSend","canReceive","isPrivateTxEnabled","maxTransactionAmount","updatedAt","saveSession","setItemAsync","JSON","stringify","getSession","getItemAsync","parse","signOut","deleteItemAsync","isWalletUnlocked","isAvailable","isAvailableAsync","item","unlockWalletWithBiometrics","hasHardware","hasHardwareAsync","isEnrolled","isEnrolledAsync","Error","result","authenticateAsync","promptMessage","fallbackLabel","disableDeviceFallback","success","encrypted","salt","decryptedData","secretKey","secretKeyArray","Uint8Array","keypair","fromSecretKey","error","message","String","setupWalletProtection","useBiometrics","getRandomValues","walletData","Array","from","biometricRequired","nonCustodial","deviceSpecific","exportable","isKeypairStoredSecurely","stored","getPublicKeyWithoutAuth","data","console","lockWalletFromMemory","deleteWalletPermanently"],"sourceRoot":"../../../src","sources":["services/authService.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+
3
+ import * as SecureStore from 'expo-secure-store';
4
+ import { StorageError } from "../errors.js";
5
+ const STORAGE_PREFIX = 'toss_intent_';
6
+
7
+ // Helper function to get all keys
8
+ async function getAllKeys() {
9
+ // expo-secure-store doesn't have a direct way to get all keys,
10
+ // so we'll need to track them manually
11
+ const keys = await SecureStore.getItemAsync(`${STORAGE_PREFIX}_keys`);
12
+ return keys ? JSON.parse(keys) : [];
13
+ }
14
+
15
+ // Helper function to save all keys
16
+ async function saveKeys(keys) {
17
+ await SecureStore.setItemAsync(`${STORAGE_PREFIX}_keys`, JSON.stringify(keys));
18
+ }
19
+ export async function secureStoreIntent(intent) {
20
+ try {
21
+ const key = `${STORAGE_PREFIX}${intent.id}`;
22
+ await SecureStore.setItemAsync(key, JSON.stringify(intent));
23
+
24
+ // Update the keys list
25
+ const keys = await getAllKeys();
26
+ if (!keys.includes(key)) {
27
+ keys.push(key);
28
+ await saveKeys(keys);
29
+ }
30
+ } catch (error) {
31
+ throw new StorageError('Failed to store intent securely', {
32
+ cause: error,
33
+ intentId: intent.id
34
+ });
35
+ }
36
+ }
37
+ export async function getSecureIntent(intentId) {
38
+ try {
39
+ const value = await SecureStore.getItemAsync(`${STORAGE_PREFIX}${intentId}`);
40
+ return value ? JSON.parse(value) : null;
41
+ } catch (error) {
42
+ throw new StorageError('Failed to retrieve intent', {
43
+ cause: error,
44
+ intentId
45
+ });
46
+ }
47
+ }
48
+ export async function getAllSecureIntents() {
49
+ try {
50
+ const keys = await getAllKeys();
51
+ const intents = await Promise.all(keys.map(async key => {
52
+ const value = await SecureStore.getItemAsync(key);
53
+ return value ? JSON.parse(value) : null;
54
+ }));
55
+ return intents.filter(Boolean);
56
+ } catch (error) {
57
+ throw new StorageError('Failed to retrieve all intents', {
58
+ cause: error
59
+ });
60
+ }
61
+ }
62
+ export async function removeSecureIntent(intentId) {
63
+ try {
64
+ const key = `${STORAGE_PREFIX}${intentId}`;
65
+ await SecureStore.deleteItemAsync(key);
66
+
67
+ // Update the keys list
68
+ const keys = await getAllKeys();
69
+ const updatedKeys = keys.filter(k => k !== key);
70
+ await saveKeys(updatedKeys);
71
+ } catch (error) {
72
+ throw new StorageError('Failed to remove intent', {
73
+ cause: error,
74
+ intentId
75
+ });
76
+ }
77
+ }
78
+ export async function clearAllSecureIntents() {
79
+ try {
80
+ const keys = await getAllKeys();
81
+ await Promise.all(keys.map(key => SecureStore.deleteItemAsync(key)));
82
+ await saveKeys([]);
83
+ } catch (error) {
84
+ throw new StorageError('Failed to clear all intents', {
85
+ cause: error
86
+ });
87
+ }
88
+ }
89
+ //# sourceMappingURL=secureStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SecureStore","StorageError","STORAGE_PREFIX","getAllKeys","keys","getItemAsync","JSON","parse","saveKeys","setItemAsync","stringify","secureStoreIntent","intent","key","id","includes","push","error","cause","intentId","getSecureIntent","value","getAllSecureIntents","intents","Promise","all","map","filter","Boolean","removeSecureIntent","deleteItemAsync","updatedKeys","k","clearAllSecureIntents"],"sourceRoot":"../../../src","sources":["storage/secureStorage.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ import AsyncStorage from "@react-native-async-storage/async-storage";
4
+ const INTENTS_KEY = "TOSS_PENDING_INTENTS";
5
+ export async function storePendingIntent(intent) {
6
+ const current = JSON.parse((await AsyncStorage.getItem(INTENTS_KEY)) || "[]");
7
+ current.push(intent);
8
+ await AsyncStorage.setItem(INTENTS_KEY, JSON.stringify(current));
9
+ }
10
+ export async function getPendingIntents() {
11
+ return JSON.parse((await AsyncStorage.getItem(INTENTS_KEY)) || "[]");
12
+ }
13
+ export async function clearPendingIntents() {
14
+ await AsyncStorage.removeItem(INTENTS_KEY);
15
+ }
16
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["AsyncStorage","INTENTS_KEY","storePendingIntent","intent","current","JSON","parse","getItem","push","setItem","stringify","getPendingIntents","clearPendingIntents","removeItem"],"sourceRoot":"../../src","sources":["storage.ts"],"mappings":";;AAAA,OAAOA,YAAY,MAAM,2CAA2C;AAEpE,MAAMC,WAAW,GAAG,sBAAsB;AAE1C,OAAO,eAAeC,kBAAkBA,CAACC,MAAW,EAAE;EACpD,MAAMC,OAAO,GAAGC,IAAI,CAACC,KAAK,CAAC,CAAC,MAAMN,YAAY,CAACO,OAAO,CAACN,WAAW,CAAC,KAAK,IAAI,CAAC;EAC7EG,OAAO,CAACI,IAAI,CAACL,MAAM,CAAC;EACpB,MAAMH,YAAY,CAACS,OAAO,CAACR,WAAW,EAAEI,IAAI,CAACK,SAAS,CAACN,OAAO,CAAC,CAAC;AAClE;AAEA,OAAO,eAAeO,iBAAiBA,CAAA,EAAG;EACxC,OAAON,IAAI,CAACC,KAAK,CAAC,CAAC,MAAMN,YAAY,CAACO,OAAO,CAACN,WAAW,CAAC,KAAK,IAAI,CAAC;AACtE;AAEA,OAAO,eAAeW,mBAAmBA,CAAA,EAAG;EAC1C,MAAMZ,YAAY,CAACa,UAAU,CAACZ,WAAW,CAAC;AAC5C","ignoreList":[]}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Synchronisation with Solana Blockchain
5
+ *
6
+ * Implements Section 9 of the TOSS Technical Paper:
7
+ * Upon regaining connectivity, devices initiate reconciliation with onchain state.
8
+ * All offline artifacts are verified onchain and settled with deterministic outcomes.
9
+ */
10
+
11
+ import { reconcilePendingIntents, detectConflicts, getReconciliationState } from "./reconciliation.js";
12
+ import { NetworkError } from "./errors.js";
13
+ /**
14
+ * Full sync and reconciliation with the Solana blockchain
15
+ *
16
+ * This is the primary function for TOSS settlement. When a device regains
17
+ * connectivity, it calls this to:
18
+ * 1. Detect any conflicts with onchain state
19
+ * 2. Settle all pending intents
20
+ * 3. Update local state with results
21
+ *
22
+ * @param connection Connection to Solana RPC
23
+ * @param feePayer Optional fee payer keypair public key
24
+ * @returns Detailed sync results including conflicts and settlements
25
+ */
26
+ export async function syncToChain(connection, feePayer) {
27
+ const syncTimestamp = Math.floor(Date.now() / 1000);
28
+ try {
29
+ // Step 1: Detect any conflicts with onchain state
30
+ const detectedConflicts = await detectConflicts(connection);
31
+
32
+ // Step 2: Reconcile and settle all pending intents
33
+ const allSettlementResults = await reconcilePendingIntents(connection, feePayer);
34
+
35
+ // Step 3: Separate successful and failed settlements
36
+ const successfulSettlements = allSettlementResults.filter(r => r.status === 'success');
37
+ const failedSettlements = allSettlementResults.filter(r => r.status !== 'success');
38
+
39
+ // Step 4: Get final reconciliation state
40
+ const reconciliationState = await getReconciliationState(connection);
41
+ const isComplete = failedSettlements.length === 0 && detectedConflicts.length === 0;
42
+ return {
43
+ successfulSettlements,
44
+ failedSettlements,
45
+ detectedConflicts,
46
+ reconciliationState,
47
+ syncTimestamp,
48
+ isComplete
49
+ };
50
+ } catch (error) {
51
+ throw new NetworkError(`Sync to chain failed: ${error instanceof Error ? error.message : String(error)}`, {
52
+ cause: error
53
+ });
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Lightweight sync to check status without settling
59
+ * Useful for monitoring or UI updates without committing to settlements
60
+ */
61
+ export async function checkSyncStatus(connection) {
62
+ return getReconciliationState(connection);
63
+ }
64
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["reconcilePendingIntents","detectConflicts","getReconciliationState","NetworkError","syncToChain","connection","feePayer","syncTimestamp","Math","floor","Date","now","detectedConflicts","allSettlementResults","successfulSettlements","filter","r","status","failedSettlements","reconciliationState","isComplete","length","error","Error","message","String","cause","checkSyncStatus"],"sourceRoot":"../../src","sources":["sync.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA,SACEA,uBAAuB,EACvBC,eAAe,EACfC,sBAAsB,QAGjB,qBAAkB;AACzB,SAASC,YAAY,QAAQ,aAAU;AAiBvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,WAAWA,CAC/BC,UAAsB,EACtBC,QAAoB,EACC;EACrB,MAAMC,aAAa,GAAGC,IAAI,CAACC,KAAK,CAACC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC;EAEnD,IAAI;IACF;IACA,MAAMC,iBAAiB,GAAG,MAAMX,eAAe,CAACI,UAAU,CAAC;;IAE3D;IACA,MAAMQ,oBAAoB,GAAG,MAAMb,uBAAuB,CACxDK,UAAU,EACVC,QACF,CAAC;;IAED;IACA,MAAMQ,qBAAqB,GAAGD,oBAAoB,CAACE,MAAM,CACtDC,CAAC,IAAKA,CAAC,CAACC,MAAM,KAAK,SACtB,CAAC;IACD,MAAMC,iBAAiB,GAAGL,oBAAoB,CAACE,MAAM,CAClDC,CAAC,IAAKA,CAAC,CAACC,MAAM,KAAK,SACtB,CAAC;;IAED;IACA,MAAME,mBAAmB,GAAG,MAAMjB,sBAAsB,CAACG,UAAU,CAAC;IAEpE,MAAMe,UAAU,GACdF,iBAAiB,CAACG,MAAM,KAAK,CAAC,IAAIT,iBAAiB,CAACS,MAAM,KAAK,CAAC;IAElE,OAAO;MACLP,qBAAqB;MACrBI,iBAAiB;MACjBN,iBAAiB;MACjBO,mBAAmB;MACnBZ,aAAa;MACba;IACF,CAAC;EACH,CAAC,CAAC,OAAOE,KAAK,EAAE;IACd,MAAM,IAAInB,YAAY,CACpB,yBAAyBmB,KAAK,YAAYC,KAAK,GAAGD,KAAK,CAACE,OAAO,GAAGC,MAAM,CAACH,KAAK,CAAC,EAAE,EACjF;MAAEI,KAAK,EAAEJ;IAAM,CACjB,CAAC;EACH;AACF;;AAEA;AACA;AACA;AACA;AACA,OAAO,eAAeK,eAAeA,CACnCtB,UAAsB,EACQ;EAC9B,OAAOH,sBAAsB,CAACG,UAAU,CAAC;AAC3C","ignoreList":[]}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+
3
+ import { PublicKey } from '@solana/web3.js';
4
+
5
+ /**
6
+ * Represents a TOSS wallet user in the ecosystem
7
+ */
8
+
9
+ /**
10
+ * Minimal user info for transaction context
11
+ */
12
+
13
+ // Example usage
14
+ export const exampleTossUser = {
15
+ userId: 'toss_abc123',
16
+ username: '@alice',
17
+ displayName: 'Alice',
18
+ wallet: {
19
+ publicKey: new PublicKey('11111111111111111111111111111111'),
20
+ // Example key
21
+ isVerified: true,
22
+ createdAt: '2023-01-01T00:00:00Z'
23
+ },
24
+ device: {
25
+ id: 'dev_xyz789',
26
+ name: 'Alice iPhone',
27
+ lastActive: new Date().toISOString(),
28
+ client: 'mobile'
29
+ },
30
+ status: 'active',
31
+ lastSeen: new Date().toISOString(),
32
+ tossFeatures: {
33
+ canSend: true,
34
+ canReceive: true,
35
+ isPrivateTxEnabled: true,
36
+ maxTransactionAmount: 1000000000 // 1 SOL in lamports
37
+ },
38
+ createdAt: '2023-01-01T00:00:00Z',
39
+ updatedAt: new Date().toISOString()
40
+ };
41
+ //# sourceMappingURL=tossUser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["PublicKey","exampleTossUser","userId","username","displayName","wallet","publicKey","isVerified","createdAt","device","id","name","lastActive","Date","toISOString","client","status","lastSeen","tossFeatures","canSend","canReceive","isPrivateTxEnabled","maxTransactionAmount","updatedAt"],"sourceRoot":"../../../src","sources":["types/tossUser.ts"],"mappings":";;AAAA,SAASA,SAAS,QAAQ,iBAAiB;;AAE3C;AACA;AACA;;AAuCA;AACA;AACA;;AASA;AACA,OAAO,MAAMC,eAAyB,GAAG;EACvCC,MAAM,EAAE,aAAa;EACrBC,QAAQ,EAAE,QAAQ;EAClBC,WAAW,EAAE,OAAO;EACpBC,MAAM,EAAE;IACNC,SAAS,EAAE,IAAIN,SAAS,CAAC,kCAAkC,CAAC;IAAE;IAC9DO,UAAU,EAAE,IAAI;IAChBC,SAAS,EAAE;EACb,CAAC;EACDC,MAAM,EAAE;IACNC,EAAE,EAAE,YAAY;IAChBC,IAAI,EAAE,cAAc;IACpBC,UAAU,EAAE,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;IACpCC,MAAM,EAAE;EACV,CAAC;EACDC,MAAM,EAAE,QAAQ;EAChBC,QAAQ,EAAE,IAAIJ,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;EAClCI,YAAY,EAAE;IACZC,OAAO,EAAE,IAAI;IACbC,UAAU,EAAE,IAAI;IAChBC,kBAAkB,EAAE,IAAI;IACxBC,oBAAoB,EAAE,UAAU,CAAE;EACpC,CAAC;EACDd,SAAS,EAAE,sBAAsB;EACjCe,SAAS,EAAE,IAAIV,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC;AACpC,CAAC","ignoreList":[]}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+
3
+ import { SystemProgram, Transaction, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js';
4
+ export async function createNonceAccount(connection, feePayer, nonceAccount = Keypair.generate(), amount = 1 * LAMPORTS_PER_SOL // 1 SOL should be enough for many transactions
5
+ ) {
6
+ const nonceAuth = feePayer.publicKey;
7
+ const tx = new Transaction().add(SystemProgram.createAccount({
8
+ fromPubkey: feePayer.publicKey,
9
+ newAccountPubkey: nonceAccount.publicKey,
10
+ lamports: amount,
11
+ space: 80,
12
+ // Size of nonce account
13
+ programId: SystemProgram.programId
14
+ }), SystemProgram.nonceInitialize({
15
+ noncePubkey: nonceAccount.publicKey,
16
+ authorizedPubkey: nonceAuth
17
+ }));
18
+ tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
19
+ tx.feePayer = feePayer.publicKey;
20
+ tx.sign(feePayer, nonceAccount);
21
+ await connection.sendRawTransaction(tx.serialize());
22
+ return {
23
+ nonceAccount,
24
+ nonceAuth
25
+ };
26
+ }
27
+ export async function getNonce(connection, nonceAccount) {
28
+ const accountInfo = await connection.getAccountInfo(nonceAccount);
29
+ if (!accountInfo) throw new Error('Nonce account not found');
30
+ return accountInfo.data.slice(32, 64).toString('hex');
31
+ }
32
+ export function createNonceAdvanceInstruction(noncePubkey, authorizedPubkey) {
33
+ return SystemProgram.nonceAdvance({
34
+ noncePubkey,
35
+ authorizedPubkey
36
+ });
37
+ }
38
+ //# sourceMappingURL=nonceUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SystemProgram","Transaction","Keypair","LAMPORTS_PER_SOL","createNonceAccount","connection","feePayer","nonceAccount","generate","amount","nonceAuth","publicKey","tx","add","createAccount","fromPubkey","newAccountPubkey","lamports","space","programId","nonceInitialize","noncePubkey","authorizedPubkey","recentBlockhash","getLatestBlockhash","blockhash","sign","sendRawTransaction","serialize","getNonce","accountInfo","getAccountInfo","Error","data","slice","toString","createNonceAdvanceInstruction","nonceAdvance"],"sourceRoot":"../../../src","sources":["utils/nonceUtils.ts"],"mappings":";;AAAA,SACEA,aAAa,EAEbC,WAAW,EAEXC,OAAO,EACPC,gBAAgB,QACX,iBAAiB;AAExB,OAAO,eAAeC,kBAAkBA,CACtCC,UAAsB,EACtBC,QAAiB,EACjBC,YAAqB,GAAGL,OAAO,CAACM,QAAQ,CAAC,CAAC,EAC1CC,MAAM,GAAG,CAAC,GAAGN,gBAAgB,CAAC;AAAA,EAC4B;EAC1D,MAAMO,SAAS,GAAGJ,QAAQ,CAACK,SAAS;EACpC,MAAMC,EAAE,GAAG,IAAIX,WAAW,CAAC,CAAC,CAACY,GAAG,CAC9Bb,aAAa,CAACc,aAAa,CAAC;IAC1BC,UAAU,EAAET,QAAQ,CAACK,SAAS;IAC9BK,gBAAgB,EAAET,YAAY,CAACI,SAAS;IACxCM,QAAQ,EAAER,MAAM;IAChBS,KAAK,EAAE,EAAE;IAAE;IACXC,SAAS,EAAEnB,aAAa,CAACmB;EAC3B,CAAC,CAAC,EACFnB,aAAa,CAACoB,eAAe,CAAC;IAC5BC,WAAW,EAAEd,YAAY,CAACI,SAAS;IACnCW,gBAAgB,EAAEZ;EACpB,CAAC,CACH,CAAC;EAEDE,EAAE,CAACW,eAAe,GAAG,CAAC,MAAMlB,UAAU,CAACmB,kBAAkB,CAAC,CAAC,EAAEC,SAAS;EACtEb,EAAE,CAACN,QAAQ,GAAGA,QAAQ,CAACK,SAAS;EAChCC,EAAE,CAACc,IAAI,CAACpB,QAAQ,EAAEC,YAAY,CAAC;EAE/B,MAAMF,UAAU,CAACsB,kBAAkB,CAACf,EAAE,CAACgB,SAAS,CAAC,CAAC,CAAC;EACnD,OAAO;IAAErB,YAAY;IAAEG;EAAU,CAAC;AACpC;AAEA,OAAO,eAAemB,QAAQA,CAC5BxB,UAAsB,EACtBE,YAAuB,EACN;EACjB,MAAMuB,WAAW,GAAG,MAAMzB,UAAU,CAAC0B,cAAc,CAACxB,YAAY,CAAC;EACjE,IAAI,CAACuB,WAAW,EAAE,MAAM,IAAIE,KAAK,CAAC,yBAAyB,CAAC;EAC5D,OAAOF,WAAW,CAACG,IAAI,CAACC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAACC,QAAQ,CAAC,KAAK,CAAC;AACvD;AAEA,OAAO,SAASC,6BAA6BA,CAC3Cf,WAAsB,EACtBC,gBAA2B,EAC3B;EACA,OAAOtB,aAAa,CAACqC,YAAY,CAAC;IAChChB,WAAW;IACXC;EACF,CAAC,CAAC;AACJ","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/index.test.tsx"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Unit Tests for TOSS Reconciliation Module
3
+ * Tests the core reconciliation and settlement logic from Section 9-10
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=reconciliation.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconciliation.test.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/reconciliation.test.tsx"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,10 @@
1
+ import { Device } from 'react-native-ble-plx';
2
+ import type { TossUser } from './types/tossUser';
3
+ import type { SolanaIntent } from './intent';
4
+ export declare function requestBLEPermissions(): Promise<void>;
5
+ export declare function startTossScan(onUserFound: (user: TossUser, device: Device) => void, onIntentFound: (intent: SolanaIntent, device: Device) => void): void;
6
+ export declare function advertiseUser(user: TossUser): Promise<void>;
7
+ export declare function stopAdvertising(): Promise<void>;
8
+ export declare function sendIntentToDevice(deviceId: string, intent: SolanaIntent): Promise<void>;
9
+ export declare function stopScan(): void;
10
+ //# sourceMappingURL=ble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ble.d.ts","sourceRoot":"","sources":["../../../src/ble.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAQ7C,wBAAsB,qBAAqB,kBAQ1C;AAUD,wBAAgB,aAAa,CAC3B,WAAW,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,EACrD,aAAa,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,QA0C9D;AAKD,wBAAsB,aAAa,CAAC,IAAI,EAAE,QAAQ,iBAuBjD;AAED,wBAAsB,eAAe,kBASpC;AAGD,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,iBAcrB;AAGD,wBAAgB,QAAQ,SAEvB"}
@@ -0,0 +1,110 @@
1
+ import { Keypair, PublicKey } from '@solana/web3.js';
2
+ import type { SolanaIntent, IntentStatus } from '../intent';
3
+ import { type SyncResult } from '../sync';
4
+ export type TossConfig = {
5
+ projectId: string;
6
+ mode?: 'devnet' | 'testnet' | 'mainnet-beta';
7
+ privateTransactions?: boolean;
8
+ provider?: any;
9
+ sync?: {
10
+ syncBackupDb?: boolean;
11
+ dbUrl?: string;
12
+ };
13
+ rpcUrl?: string;
14
+ maxRetries?: number;
15
+ retryDelay?: number;
16
+ feePayer?: Keypair;
17
+ };
18
+ export declare class TossClient {
19
+ private connection;
20
+ private config;
21
+ private nonceAccount?;
22
+ private nonceAuth?;
23
+ private walletContext;
24
+ static createClient(config: TossConfig): TossClient;
25
+ private constructor();
26
+ private getDefaultRpcUrl;
27
+ private withRetry;
28
+ /**
29
+ * Initialize a nonce account for durable transactions
30
+ * @param amount SOL amount to fund the nonce account with (default: 1 SOL)
31
+ * @returns Object containing nonce account and authority public keys
32
+ */
33
+ initializeNonceAccount(amount?: number): Promise<{
34
+ nonceAccount: string;
35
+ nonceAuth: string;
36
+ }>;
37
+ /**
38
+ * Get the current nonce value from the nonce account
39
+ * @returns The current nonce value as a base58 string
40
+ */
41
+ getCurrentNonce(): Promise<string>;
42
+ createIntent(sender: Keypair | 'current', recipient: PublicKey | string, amount: number, feePayer?: PublicKey | string, options?: {
43
+ expiresIn?: number;
44
+ nonce?: number;
45
+ useDurableNonce?: boolean;
46
+ memo?: string;
47
+ }): Promise<SolanaIntent>;
48
+ getIntents(): Promise<SolanaIntent[]>;
49
+ updateIntentStatus(intentId: string, status: IntentStatus, error?: string): Promise<SolanaIntent | null>;
50
+ sync(): Promise<SolanaIntent[]>;
51
+ /**
52
+ * Full synchronisation with Solana blockchain (TOSS Section 9)
53
+ *
54
+ * Performs complete reconciliation:
55
+ * - Detects conflicts with onchain state
56
+ * - Settles all pending intents
57
+ * - Updates local state deterministically
58
+ *
59
+ * @returns Complete sync results including settlements, conflicts, and final state
60
+ */
61
+ fullSync(): Promise<SyncResult>;
62
+ /**
63
+ * Check synchronisation status without settling
64
+ *
65
+ * Lightweight operation to query current reconciliation state
66
+ * without committing any settlements to the blockchain.
67
+ */
68
+ checkSyncStatus(): Promise<import("..").ReconciliationState>;
69
+ /**
70
+ * Detect conflicts between local intents and onchain state
71
+ *
72
+ * Useful for monitoring and alerting users to potential issues
73
+ * before attempting settlement.
74
+ */
75
+ detectIntentConflicts(): Promise<{
76
+ intentId: string;
77
+ conflict: string;
78
+ }[]>;
79
+ /**
80
+ * Get current reconciliation state
81
+ *
82
+ * Returns summary of processed, failed, and conflicting intents
83
+ * for UI updates or logging.
84
+ */
85
+ getReconciliationStatus(): Promise<import("..").ReconciliationState>;
86
+ /**
87
+ * Create an intent from the current user's wallet
88
+ */
89
+ createUserIntent(recipient: PublicKey | string, amount: number, options?: {
90
+ memo?: string;
91
+ useDurableNonce?: boolean;
92
+ }): Promise<SolanaIntent>;
93
+ /**
94
+ * Get the current user's wallet address
95
+ */
96
+ getCurrentUserAddress(): string | null;
97
+ /**
98
+ * Check if the wallet is currently unlocked
99
+ */
100
+ isWalletUnlocked(): boolean;
101
+ /**
102
+ * Lock the wallet
103
+ */
104
+ lockWallet(): Promise<void>;
105
+ /**
106
+ * Sign out the current user
107
+ */
108
+ signOut(): Promise<void>;
109
+ }
110
+ //# sourceMappingURL=TossClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TossClient.d.ts","sourceRoot":"","sources":["../../../../src/client/TossClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAW5D,OAAO,EAAgC,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAGxE,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,cAAc,CAAC;IAC7C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,IAAI,CAAC,EAAE;QACL,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAOF,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAGZ;IACF,OAAO,CAAC,YAAY,CAAC,CAAU;IAC/B,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,aAAa,CAA+B;IAEpD,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU;IAInD,OAAO;IAoBP,OAAO,CAAC,gBAAgB;YASV,SAAS;IAgCvB;;;;OAIG;IACG,sBAAsB,CAC1B,MAAM,SAAI,GACT,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAuBvD;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;IASlC,YAAY,CAChB,MAAM,EAAE,OAAO,GAAG,SAAS,EAC3B,SAAS,EAAE,SAAS,GAAG,MAAM,EAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,EAC7B,OAAO,GAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;KACV,GACL,OAAO,CAAC,YAAY,CAAC;IAmElB,UAAU,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAWrC,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,YAAY,EACpB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IA6BzB,IAAI,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IA4BrC;;;;;;;;;OASG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IAcrC;;;;;OAKG;IACG,eAAe;IAMrB;;;;;OAKG;IACG,qBAAqB;;;;IAM3B;;;;;OAKG;IACG,uBAAuB;IAM7B;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,SAAS,GAAG,MAAM,EAC7B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,eAAe,CAAC,EAAE,OAAO,CAAC;KACtB,GACL,OAAO,CAAC,YAAY,CAAC;IAkCxB;;OAEG;IACH,qBAAqB,IAAI,MAAM,GAAG,IAAI;IAItC;;OAEG;IACH,gBAAgB,IAAI,OAAO;IAI3B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}