@thru/wallet 0.2.25 → 0.2.28

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 (47) hide show
  1. package/README.md +1 -0
  2. package/dist/{BrowserSDK-CpRFiJsW.d.ts → BrowserSDK-CRQTOT8S.d.ts} +178 -3
  3. package/dist/index.d.ts +2 -2
  4. package/dist/index.js +376 -12
  5. package/dist/index.js.map +1 -1
  6. package/dist/native/react/transparent.d.ts +104 -0
  7. package/dist/native/react/transparent.js +2210 -0
  8. package/dist/native/react/transparent.js.map +1 -0
  9. package/dist/native/react.d.ts +5 -90
  10. package/dist/native/react.js +765 -32
  11. package/dist/native/react.js.map +1 -1
  12. package/dist/native.d.ts +105 -1
  13. package/dist/native.js +521 -31
  14. package/dist/native.js.map +1 -1
  15. package/dist/react-ui.js +5 -0
  16. package/dist/react-ui.js.map +1 -1
  17. package/dist/react.d.ts +2 -2
  18. package/dist/react.js +376 -12
  19. package/dist/react.js.map +1 -1
  20. package/package.json +8 -2
  21. package/src/BrowserSDK.ts +32 -1
  22. package/src/encoding.ts +39 -0
  23. package/src/index.ts +5 -1
  24. package/src/interfaces/IThruChain.ts +50 -1
  25. package/src/interfaces/types.ts +52 -0
  26. package/src/native/NativeSDK.test.ts +200 -1
  27. package/src/native/NativeSDK.ts +124 -10
  28. package/src/native/index.ts +12 -0
  29. package/src/native/provider/NativeProvider.ts +106 -5
  30. package/src/native/provider/WebViewBridge.test.ts +22 -1
  31. package/src/native/provider/WebViewBridge.ts +17 -7
  32. package/src/native/provider/chains/ThruChain.ts +215 -5
  33. package/src/native/react/ThruContext.ts +3 -1
  34. package/src/native/react/ThruProvider.tsx +25 -0
  35. package/src/native/react/ThruTransparentWalletBridge.tsx +281 -0
  36. package/src/native/react/hooks/useWallet.ts +12 -1
  37. package/src/native/react/index.ts +11 -0
  38. package/src/native/react/transparent.ts +35 -0
  39. package/src/protocol/postMessage.ts +127 -2
  40. package/src/provider/EmbeddedProvider.ts +7 -1
  41. package/src/provider/IframeManager.test.ts +18 -0
  42. package/src/provider/IframeManager.ts +8 -1
  43. package/src/provider/chains/ThruChain.ts +210 -4
  44. package/src/provider/types/messages.ts +16 -0
  45. package/src/react/index.ts +6 -0
  46. package/src/signing-sessions.test.ts +182 -0
  47. package/src/signing-sessions.ts +204 -0
@@ -49,14 +49,20 @@ var AddressType = {
49
49
  // src/protocol/postMessage.ts
50
50
  var POST_MESSAGE_REQUEST_TYPES = {
51
51
  CONNECT: "connect",
52
+ CREATE_ACCOUNT: "createAccount",
52
53
  DISCONNECT: "disconnect",
53
54
  SIGN_MESSAGE: "signMessage",
54
55
  SIGN_TRANSACTION: "signTransaction",
56
+ SIGN_PASSKEY_CHALLENGE: "signPasskeyChallenge",
55
57
  GET_ACCOUNTS: "getAccounts",
56
58
  GET_CONNECTION_STATE: "getConnectionState",
57
59
  GET_SIGNING_CONTEXT: "getSigningContext",
58
60
  SELECT_ACCOUNT: "selectAccount",
59
- MANAGE_ACCOUNTS: "manageAccounts"
61
+ MANAGE_ACCOUNTS: "manageAccounts",
62
+ CREATE_SIGNING_SESSION: "createSigningSession",
63
+ CREATE_SIGNING_SESSION_INSTRUCTION: "createSigningSessionInstruction",
64
+ CONFIRM_SIGNING_SESSION: "confirmSigningSession",
65
+ REVOKE_SIGNING_SESSION: "revokeSigningSession"
60
66
  };
61
67
  var EMBEDDED_PROVIDER_EVENTS = {
62
68
  CONNECT_START: "connect_start",
@@ -86,12 +92,195 @@ function normalizeConnectionStateResult(result) {
86
92
  return normalizeWalletAccountResult(result);
87
93
  }
88
94
 
95
+ // src/encoding.ts
96
+ var BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
97
+ var BASE64_LOOKUP = new Map(
98
+ [...BASE64_ALPHABET].map((char, index) => [char, index])
99
+ );
100
+ function base64ToBytes(value) {
101
+ const normalized = value.replace(/\s+/g, "");
102
+ if (normalized.length === 0) return new Uint8Array();
103
+ if (normalized.length % 4 === 1) {
104
+ throw new Error("Invalid base64 data");
105
+ }
106
+ const padded = normalized.padEnd(
107
+ normalized.length + (4 - normalized.length % 4) % 4,
108
+ "="
109
+ );
110
+ const padding = padded.endsWith("==") ? 2 : padded.endsWith("=") ? 1 : 0;
111
+ const output = new Uint8Array(padded.length / 4 * 3 - padding);
112
+ let outIdx = 0;
113
+ for (let i = 0; i < padded.length; i += 4) {
114
+ const chars = padded.slice(i, i + 4);
115
+ const a = BASE64_LOOKUP.get(chars[0]);
116
+ const b = BASE64_LOOKUP.get(chars[1]);
117
+ const c = chars[2] === "=" ? 0 : BASE64_LOOKUP.get(chars[2]);
118
+ const d = chars[3] === "=" ? 0 : BASE64_LOOKUP.get(chars[3]);
119
+ if (a === void 0 || b === void 0 || c === void 0 || d === void 0) {
120
+ throw new Error("Invalid base64 data");
121
+ }
122
+ const chunk = a << 18 | b << 12 | c << 6 | d;
123
+ if (outIdx < output.length) output[outIdx++] = chunk >> 16 & 255;
124
+ if (outIdx < output.length) output[outIdx++] = chunk >> 8 & 255;
125
+ if (outIdx < output.length) output[outIdx++] = chunk & 255;
126
+ }
127
+ return output;
128
+ }
129
+
130
+ // src/signing-sessions.ts
131
+ var STORAGE_VERSION = 1;
132
+ var KEY_PREFIX = "thru.wallet.signing-sessions.v1";
133
+ function encodeKeyPart(input) {
134
+ return encodeURIComponent(input).replace(
135
+ /[!'()*]/g,
136
+ (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
137
+ );
138
+ }
139
+ function nowSeconds() {
140
+ return Math.floor(Date.now() / 1e3);
141
+ }
142
+ function resolveSigningSessionStorageKey(params) {
143
+ if (params.storageKey) return params.storageKey;
144
+ return `${KEY_PREFIX}:${encodeKeyPart(params.walletOrigin)}:${encodeKeyPart(params.appOrigin)}`;
145
+ }
146
+ function normalizeExpiresAt(value, label = "expiresAt") {
147
+ if (value instanceof Date) {
148
+ const millis = value.getTime();
149
+ if (!Number.isFinite(millis)) throw new Error(`${label} must be a valid Date`);
150
+ return Math.floor(millis / 1e3);
151
+ }
152
+ if (typeof value === "bigint") {
153
+ if (value < 0n || value > BigInt(Number.MAX_SAFE_INTEGER)) {
154
+ throw new Error(`${label} must fit in a JavaScript safe integer`);
155
+ }
156
+ return Number(value);
157
+ }
158
+ if (typeof value === "string") {
159
+ const trimmed = value.trim();
160
+ if (!/^\d+$/.test(trimmed)) {
161
+ throw new Error(`${label} must be a Unix timestamp in seconds`);
162
+ }
163
+ return normalizeExpiresAt(BigInt(trimmed), label);
164
+ }
165
+ if (!Number.isFinite(value) || value < 0) {
166
+ throw new Error(`${label} must be a finite positive Unix timestamp`);
167
+ }
168
+ return Math.floor(value);
169
+ }
170
+ function resolveSessionExpirySeconds(options) {
171
+ const hasDuration = options.durationSeconds !== void 0;
172
+ const hasExpiresAt = options.expiresAt !== void 0;
173
+ if (hasDuration === hasExpiresAt) {
174
+ throw new Error("Provide exactly one of durationSeconds or expiresAt");
175
+ }
176
+ if (hasDuration) {
177
+ const duration = options.durationSeconds;
178
+ if (typeof duration !== "number" || !Number.isFinite(duration) || duration <= 0) {
179
+ throw new Error("durationSeconds must be a positive number");
180
+ }
181
+ return nowSeconds() + Math.floor(duration);
182
+ }
183
+ return normalizeExpiresAt(options.expiresAt, "expiresAt");
184
+ }
185
+ function assertSigningSessionWalletAccountIdx(walletAccountIdx) {
186
+ if (!Number.isInteger(walletAccountIdx) || walletAccountIdx < 2 || walletAccountIdx > 65535) {
187
+ throw new Error("walletAccountIdx must be an account index between 2 and 65535");
188
+ }
189
+ }
190
+ function normalizeDescriptor(descriptor) {
191
+ return {
192
+ id: descriptor.id,
193
+ walletAddress: descriptor.walletAddress,
194
+ publicKey: descriptor.publicKey,
195
+ authIdx: Number(descriptor.authIdx),
196
+ expiresAt: normalizeExpiresAt(descriptor.expiresAt, "descriptor.expiresAt"),
197
+ createdAt: normalizeExpiresAt(descriptor.createdAt, "descriptor.createdAt")
198
+ };
199
+ }
200
+ function isActive(descriptor) {
201
+ return nowSeconds() < descriptor.expiresAt;
202
+ }
203
+ var SigningSessionDescriptorStore = class {
204
+ constructor(storage, key) {
205
+ this.storage = storage;
206
+ this.key = key;
207
+ }
208
+ async list() {
209
+ const sessions = await this.read();
210
+ const active = sessions.filter(isActive);
211
+ if (active.length !== sessions.length) {
212
+ await this.write(active);
213
+ }
214
+ return active;
215
+ }
216
+ async get(id) {
217
+ const sessions = await this.list();
218
+ return sessions.find((session) => session.id === id) ?? null;
219
+ }
220
+ async save(descriptor) {
221
+ const normalized = normalizeDescriptor(descriptor);
222
+ const sessions = (await this.list()).filter((session) => session.id !== normalized.id);
223
+ sessions.push(normalized);
224
+ await this.write(sessions);
225
+ }
226
+ async saveReplacingWalletSessions(descriptor) {
227
+ const normalized = normalizeDescriptor(descriptor);
228
+ const sessions = (await this.list()).filter(
229
+ (session) => session.id === normalized.id || session.walletAddress !== normalized.walletAddress
230
+ );
231
+ const withoutCurrent = sessions.filter((session) => session.id !== normalized.id);
232
+ withoutCurrent.push(normalized);
233
+ await this.write(withoutCurrent);
234
+ }
235
+ async remove(id) {
236
+ const sessions = (await this.list()).filter((session) => session.id !== id);
237
+ if (sessions.length === 0) {
238
+ await this.storage.removeItem(this.key);
239
+ return;
240
+ }
241
+ await this.write(sessions);
242
+ }
243
+ async read() {
244
+ const raw = await this.storage.getItem(this.key);
245
+ if (!raw) return [];
246
+ try {
247
+ const parsed = JSON.parse(raw);
248
+ if (parsed.version !== STORAGE_VERSION || !Array.isArray(parsed.sessions)) {
249
+ await this.storage.removeItem(this.key);
250
+ return [];
251
+ }
252
+ return parsed.sessions.map(normalizeDescriptor);
253
+ } catch {
254
+ await this.storage.removeItem(this.key);
255
+ return [];
256
+ }
257
+ }
258
+ async write(sessions) {
259
+ const payload = {
260
+ version: STORAGE_VERSION,
261
+ sessions: sessions.map(normalizeDescriptor)
262
+ };
263
+ await this.storage.setItem(this.key, JSON.stringify(payload));
264
+ }
265
+ };
266
+
89
267
  // src/native/provider/chains/ThruChain.ts
268
+ function descriptorFromWire(session) {
269
+ return {
270
+ id: session.id,
271
+ walletAddress: session.walletAddress,
272
+ publicKey: session.publicKey,
273
+ authIdx: session.authIdx,
274
+ expiresAt: Number(BigInt(session.expiresAt)),
275
+ createdAt: Number(BigInt(session.createdAt))
276
+ };
277
+ }
90
278
  var NativeThruChain = class {
91
- constructor(bridge, provider, origin) {
279
+ constructor(bridge, provider, origin, signingSessions) {
92
280
  this.bridge = bridge;
93
281
  this.provider = provider;
94
282
  this.origin = origin;
283
+ this.signingSessions = signingSessions;
95
284
  }
96
285
  get connected() {
97
286
  return this.provider.isConnected();
@@ -109,7 +298,7 @@ var NativeThruChain = class {
109
298
  await this.provider.disconnect();
110
299
  }
111
300
  async getSigningContext() {
112
- if (!this.provider.isConnected()) {
301
+ if (!this.provider.isConnected() && !this.provider.isTransparent()) {
113
302
  throw new Error("Wallet not connected");
114
303
  }
115
304
  const response = await this.bridge.sendMessage({
@@ -120,33 +309,179 @@ var NativeThruChain = class {
120
309
  return response.result.signingContext;
121
310
  }
122
311
  async signTransaction(transaction) {
123
- if (!this.provider.isConnected()) {
312
+ const signingSessionId = transaction.signingSessionId;
313
+ if (!signingSessionId && !this.provider.isConnected() && !this.provider.isTransparent()) {
124
314
  throw new Error("Wallet not connected");
125
315
  }
126
- this.provider.requestShow();
316
+ const session = signingSessionId ? await this.requireSigningSession(signingSessionId) : null;
317
+ const shouldShowWallet = !signingSessionId;
318
+ if (shouldShowWallet) {
319
+ await this.provider.requestShow();
320
+ }
127
321
  try {
128
322
  const response = await this.bridge.sendMessage({
129
323
  id: createRequestId(),
130
324
  type: POST_MESSAGE_REQUEST_TYPES.SIGN_TRANSACTION,
131
325
  payload: {
132
- walletAddress: transaction.walletAddress,
326
+ walletAddress: transaction.walletAddress ?? session?.walletAddress,
133
327
  programAddress: transaction.programAddress,
134
328
  instructionData: transaction.instructionData,
135
329
  readWriteAddresses: transaction.readWriteAddresses,
136
330
  readOnlyAddresses: transaction.readOnlyAddresses,
137
- review: transaction.review
331
+ review: transaction.review,
332
+ signingSessionId
138
333
  },
139
334
  origin: this.origin
140
335
  });
141
336
  return response.result.signedTransaction;
337
+ } finally {
338
+ if (shouldShowWallet) {
339
+ this.provider.requestHide();
340
+ }
341
+ }
342
+ }
343
+ async signPasskeyChallenge(challenge) {
344
+ if (!this.provider.isConnected() && !this.provider.isTransparent()) {
345
+ throw new Error("Wallet not connected");
346
+ }
347
+ await this.provider.requestShow();
348
+ try {
349
+ const response = await this.bridge.sendMessage({
350
+ id: createRequestId(),
351
+ type: POST_MESSAGE_REQUEST_TYPES.SIGN_PASSKEY_CHALLENGE,
352
+ payload: {
353
+ challenge: challenge.challenge,
354
+ walletAddress: challenge.walletAddress
355
+ },
356
+ origin: this.origin
357
+ });
358
+ return response.result;
142
359
  } finally {
143
360
  this.provider.requestHide();
144
361
  }
145
362
  }
363
+ async createSigningSession(options) {
364
+ if (!this.provider.isConnected()) {
365
+ throw new Error("Wallet not connected");
366
+ }
367
+ if (!this.signingSessions) {
368
+ throw new Error("NativeSDKStorage is required for signing sessions");
369
+ }
370
+ const expiresAt = resolveSessionExpirySeconds(options);
371
+ await this.provider.requestShow();
372
+ try {
373
+ const response = await this.bridge.sendMessage({
374
+ id: createRequestId(),
375
+ type: POST_MESSAGE_REQUEST_TYPES.CREATE_SIGNING_SESSION,
376
+ payload: {
377
+ walletAddress: options.walletAddress,
378
+ expiresAt: String(expiresAt),
379
+ review: options.review
380
+ },
381
+ origin: this.origin
382
+ });
383
+ const descriptor = descriptorFromWire(response.result.session);
384
+ await this.signingSessions.saveReplacingWalletSessions(descriptor);
385
+ return this.toSigningSession(descriptor);
386
+ } finally {
387
+ this.provider.requestHide();
388
+ }
389
+ }
390
+ async createSigningSessionInstruction(options) {
391
+ if (!this.provider.isConnected()) {
392
+ throw new Error("Wallet not connected");
393
+ }
394
+ if (!this.signingSessions) {
395
+ throw new Error("NativeSDKStorage is required for signing sessions");
396
+ }
397
+ const expiresAt = resolveSessionExpirySeconds(options);
398
+ assertSigningSessionWalletAccountIdx(options.walletAccountIdx);
399
+ const response = await this.bridge.sendMessage({
400
+ id: createRequestId(),
401
+ type: POST_MESSAGE_REQUEST_TYPES.CREATE_SIGNING_SESSION_INSTRUCTION,
402
+ payload: {
403
+ walletAddress: options.walletAddress,
404
+ expiresAt: String(expiresAt),
405
+ walletAccountIdx: options.walletAccountIdx
406
+ },
407
+ origin: this.origin
408
+ });
409
+ const descriptor = descriptorFromWire(response.result.session);
410
+ return {
411
+ session: this.toSigningSession(descriptor),
412
+ programAddress: response.result.programAddress,
413
+ instructionData: base64ToBytes(response.result.instructionData)
414
+ };
415
+ }
416
+ async confirmSigningSession(id) {
417
+ if (!this.provider.isConnected()) {
418
+ throw new Error("Wallet not connected");
419
+ }
420
+ if (!this.signingSessions) {
421
+ throw new Error("NativeSDKStorage is required for signing sessions");
422
+ }
423
+ const response = await this.bridge.sendMessage({
424
+ id: createRequestId(),
425
+ type: POST_MESSAGE_REQUEST_TYPES.CONFIRM_SIGNING_SESSION,
426
+ payload: { sessionId: id },
427
+ origin: this.origin
428
+ });
429
+ const descriptor = descriptorFromWire(response.result.session);
430
+ await this.signingSessions.saveReplacingWalletSessions(descriptor);
431
+ return this.toSigningSession(descriptor);
432
+ }
433
+ async getSigningSession(id) {
434
+ if (!this.signingSessions) return null;
435
+ const descriptor = await this.signingSessions.get(id);
436
+ return descriptor ? this.toSigningSession(descriptor) : null;
437
+ }
438
+ async getSigningSessions() {
439
+ if (!this.signingSessions) return [];
440
+ return (await this.signingSessions.list()).map(
441
+ (descriptor) => this.toSigningSession(descriptor)
442
+ );
443
+ }
444
+ async revokeSigningSession(id) {
445
+ try {
446
+ await this.bridge.sendMessage({
447
+ id: createRequestId(),
448
+ type: POST_MESSAGE_REQUEST_TYPES.REVOKE_SIGNING_SESSION,
449
+ payload: { sessionId: id },
450
+ origin: this.origin
451
+ });
452
+ } finally {
453
+ await this.signingSessions?.remove(id);
454
+ }
455
+ }
456
+ async requireSigningSession(id) {
457
+ if (!this.signingSessions) {
458
+ throw new Error("NativeSDKStorage is required for signing sessions");
459
+ }
460
+ const session = await this.signingSessions.get(id);
461
+ if (!session) {
462
+ throw new Error("Signing session is not known to this app");
463
+ }
464
+ return session;
465
+ }
466
+ toSigningSession(descriptor) {
467
+ return {
468
+ ...descriptor,
469
+ signTransaction: (transaction) => this.signTransaction({
470
+ ...transaction,
471
+ walletAddress: transaction.walletAddress ?? descriptor.walletAddress,
472
+ signingSessionId: descriptor.id
473
+ }),
474
+ revoke: () => this.revokeSigningSession(descriptor.id),
475
+ toJSON: () => ({ ...descriptor })
476
+ };
477
+ }
146
478
  };
147
479
 
148
480
  // src/native/provider/WebViewBridge.ts
149
- var PRODUCTION_WALLET_ORIGINS = ["https://wallet.thru.org"];
481
+ var PRODUCTION_WALLET_ORIGINS = [
482
+ "https://wallet.thru.org",
483
+ "https://wallet.tid.sh"
484
+ ];
150
485
  function isDevelopmentBuild() {
151
486
  const runtime = globalThis;
152
487
  const devFlag = runtime.__DEV__;
@@ -184,14 +519,23 @@ function validateWalletOrigin(walletUrl) {
184
519
  );
185
520
  }
186
521
  }
522
+ function isNativeEmbeddedWalletPath(pathname) {
523
+ const normalized = pathname.replace(/\/+$/, "") || "/";
524
+ return normalized === "/embedded/native" || normalized.startsWith("/embedded/native/");
525
+ }
187
526
  var READY_TIMEOUT_MS = 1e4;
188
527
  var SLOW_REQUEST_TIMEOUT_MS = 5 * 60 * 1e3;
189
528
  var FAST_REQUEST_TIMEOUT_MS = 30 * 1e3;
190
529
  var SLOW_REQUEST_TYPES = /* @__PURE__ */ new Set([
191
530
  POST_MESSAGE_REQUEST_TYPES.CONNECT,
531
+ POST_MESSAGE_REQUEST_TYPES.CREATE_ACCOUNT,
192
532
  POST_MESSAGE_REQUEST_TYPES.SIGN_MESSAGE,
193
533
  POST_MESSAGE_REQUEST_TYPES.SIGN_TRANSACTION,
194
- POST_MESSAGE_REQUEST_TYPES.MANAGE_ACCOUNTS
534
+ POST_MESSAGE_REQUEST_TYPES.SIGN_PASSKEY_CHALLENGE,
535
+ POST_MESSAGE_REQUEST_TYPES.MANAGE_ACCOUNTS,
536
+ POST_MESSAGE_REQUEST_TYPES.CREATE_SIGNING_SESSION,
537
+ POST_MESSAGE_REQUEST_TYPES.CREATE_SIGNING_SESSION_INSTRUCTION,
538
+ POST_MESSAGE_REQUEST_TYPES.CONFIRM_SIGNING_SESSION
195
539
  ]);
196
540
  var WebViewBridge = class {
197
541
  constructor(options) {
@@ -213,7 +557,7 @@ var WebViewBridge = class {
213
557
  */
214
558
  getIframeSrc() {
215
559
  const url = new URL(this.walletUrl);
216
- if (!url.pathname.endsWith("/native")) {
560
+ if (!isNativeEmbeddedWalletPath(url.pathname)) {
217
561
  url.pathname = `${url.pathname.replace(/\/$/, "")}/native`;
218
562
  }
219
563
  url.searchParams.set("tn_frame_id", this.frameId);
@@ -293,14 +637,11 @@ var WebViewBridge = class {
293
637
  }
294
638
  });
295
639
  const script = `try {
296
- var msg = ${JSON.stringify(request)};
640
+ var msg = ${JSON.stringify({ ...request, frameId: this.frameId })};
297
641
  if (window.__pushIn) {
298
642
  window.__pushIn(msg);
299
643
  } else {
300
- window.dispatchEvent(new MessageEvent('message', {
301
- data: msg,
302
- origin: msg.origin || ''
303
- }));
644
+ window.postMessage(msg, window.location.origin);
304
645
  }
305
646
  } catch (e) {} ; true;`;
306
647
  this.webView.injectJavaScript(script);
@@ -376,11 +717,13 @@ var WebViewBridge = class {
376
717
  // src/native/provider/NativeProvider.ts
377
718
  var DEFAULT_WALLET_URL = "https://wallet.thru.org/embedded/native";
378
719
  var DEFAULT_ORIGIN = "thru-mobile://app";
720
+ var TRANSPARENT_FOCUS_SETTLE_MS = 500;
379
721
  var NativeProvider = class {
380
722
  constructor(config = {}) {
381
723
  this.connected = false;
382
724
  this.accounts = [];
383
725
  this.selectedAccount = null;
726
+ this.isSurfaceShown = false;
384
727
  this.eventListeners = /* @__PURE__ */ new Map();
385
728
  /** Pass through the WebView's `onMessage` event handler. */
386
729
  this.onMessage = (event) => {
@@ -388,8 +731,12 @@ var NativeProvider = class {
388
731
  };
389
732
  const walletUrl = config.walletUrl ?? DEFAULT_WALLET_URL;
390
733
  this.origin = config.origin ?? DEFAULT_ORIGIN;
734
+ this.transparent = config.walletExperience === "transparent";
391
735
  this.bridge = new WebViewBridge({ walletUrl });
392
736
  this.bridge.onEvent = (eventType, payload) => {
737
+ if (this.transparent && eventType === EMBEDDED_PROVIDER_EVENTS.UI_SHOW) {
738
+ return;
739
+ }
393
740
  this.emit(eventType, payload);
394
741
  if (eventType === EMBEDDED_PROVIDER_EVENTS.UI_SHOW) {
395
742
  this.requestShow();
@@ -407,7 +754,12 @@ var NativeProvider = class {
407
754
  };
408
755
  const addressTypes = config.addressTypes ?? [AddressType.THRU];
409
756
  if (addressTypes.includes(AddressType.THRU)) {
410
- this._thruChain = new NativeThruChain(this.bridge, this, this.origin);
757
+ this._thruChain = new NativeThruChain(
758
+ this.bridge,
759
+ this,
760
+ this.origin,
761
+ config.signingSessions
762
+ );
411
763
  }
412
764
  }
413
765
  /** Hand the bridge a WebView ref. Required before connect/sign. */
@@ -432,12 +784,27 @@ var NativeProvider = class {
432
784
  async initialize() {
433
785
  await this.bridge.awaitReady();
434
786
  }
435
- /** Open the wallet UI (called internally; also exposed for host). */
436
- requestShow() {
787
+ /** Open or focus the wallet host surface. Transparent hosts use this
788
+ to give WKWebView a focused document for WebAuthn without showing
789
+ wallet UI. */
790
+ async requestShow() {
791
+ if (this.transparent) {
792
+ if (!this.isSurfaceShown) {
793
+ this.isSurfaceShown = true;
794
+ this.onShowRequested?.();
795
+ }
796
+ await new Promise(
797
+ (resolve) => setTimeout(resolve, TRANSPARENT_FOCUS_SETTLE_MS)
798
+ );
799
+ return;
800
+ }
801
+ if (this.isSurfaceShown) return;
802
+ this.isSurfaceShown = true;
437
803
  this.onShowRequested?.();
438
804
  }
439
805
  /** Close the wallet UI (called internally; also exposed for host). */
440
806
  requestHide() {
807
+ this.isSurfaceShown = false;
441
808
  this.onHideRequested?.();
442
809
  }
443
810
  /** Reject pending requests after a user-driven native sheet dismiss. */
@@ -447,7 +814,7 @@ var NativeProvider = class {
447
814
  async connect(options) {
448
815
  this.emit(EMBEDDED_PROVIDER_EVENTS.CONNECT_START, {});
449
816
  try {
450
- this.requestShow();
817
+ await this.requestShow();
451
818
  const payload = {};
452
819
  if (options?.metadata) payload.metadata = options.metadata;
453
820
  if (options?.preferredAccountAddress) {
@@ -461,6 +828,9 @@ var NativeProvider = class {
461
828
  origin: this.origin
462
829
  });
463
830
  const result = normalizeWalletAccountResult(response.result);
831
+ if (!result.selectedAccount) {
832
+ throw new Error("Wallet did not return an account");
833
+ }
464
834
  this.connected = true;
465
835
  this.accounts = result.accounts;
466
836
  this.selectedAccount = result.selectedAccount;
@@ -473,6 +843,52 @@ var NativeProvider = class {
473
843
  throw error;
474
844
  }
475
845
  }
846
+ async createAccount(options) {
847
+ try {
848
+ await this.requestShow();
849
+ const payload = {};
850
+ if (options?.accountName) payload.accountName = options.accountName;
851
+ if (options?.metadata) payload.metadata = options.metadata;
852
+ const response = await this.bridge.sendMessage({
853
+ id: createRequestId(),
854
+ type: POST_MESSAGE_REQUEST_TYPES.CREATE_ACCOUNT,
855
+ payload,
856
+ origin: this.origin
857
+ });
858
+ const normalized = normalizeWalletAccountResult(
859
+ response.result,
860
+ response.result.selectedAccount ?? response.result.account
861
+ );
862
+ const selectedAccount = normalized.selectedAccount ?? response.result.account;
863
+ if (!selectedAccount) {
864
+ throw new Error("Wallet did not return a created account");
865
+ }
866
+ const result = {
867
+ ...response.result,
868
+ accounts: normalized.accounts,
869
+ selectedAccount,
870
+ account: selectedAccount
871
+ };
872
+ this.connected = true;
873
+ this.accounts = result.accounts;
874
+ this.selectedAccount = result.selectedAccount;
875
+ this.emit(EMBEDDED_PROVIDER_EVENTS.CONNECT, {
876
+ accounts: result.accounts,
877
+ selectedAccount: result.selectedAccount,
878
+ status: "completed",
879
+ metadata: options?.metadata
880
+ });
881
+ this.emit(EMBEDDED_PROVIDER_EVENTS.ACCOUNT_CHANGED, {
882
+ account: result.selectedAccount
883
+ });
884
+ this.requestHide();
885
+ return result;
886
+ } catch (error) {
887
+ this.requestHide();
888
+ this.emit(EMBEDDED_PROVIDER_EVENTS.ERROR, { error });
889
+ throw error;
890
+ }
891
+ }
476
892
  async getConnectionState(options) {
477
893
  const payload = {};
478
894
  if (options?.metadata) payload.metadata = options.metadata;
@@ -521,6 +937,9 @@ var NativeProvider = class {
521
937
  isConnected() {
522
938
  return this.connected;
523
939
  }
940
+ isTransparent() {
941
+ return this.transparent;
942
+ }
524
943
  hydrateConnection(result, selectedAccountAddress) {
525
944
  const selectedAccount = resolveWalletAccountByAddress(result.accounts, selectedAccountAddress) ?? result.selectedAccount ?? null;
526
945
  const normalized = normalizeWalletAccountResult(result, selectedAccount);
@@ -555,7 +974,7 @@ var NativeProvider = class {
555
974
  async manageAccounts() {
556
975
  if (!this.connected) throw new Error("Wallet not connected");
557
976
  try {
558
- this.requestShow();
977
+ await this.requestShow();
559
978
  const response = await this.bridge.sendMessage({
560
979
  id: createRequestId(),
561
980
  type: POST_MESSAGE_REQUEST_TYPES.MANAGE_ACCOUNTS,
@@ -617,6 +1036,9 @@ var NativeProvider = class {
617
1036
  };
618
1037
  var DEFAULT_STORAGE_KEY = "thru.native-sdk.connection.v1";
619
1038
  var SELECTED_ACCOUNT_STORAGE_KEY_SUFFIX = ".selected-account.v1";
1039
+ var SIGNING_SESSION_STORAGE_KEY_SUFFIX = ".signing-sessions.v1";
1040
+ var DEFAULT_NATIVE_WALLET_URL = "https://wallet.thru.org/embedded/native";
1041
+ var DEFAULT_TRANSPARENT_WALLET_URL = "https://wallet.thru.org/embedded/native/transparent";
620
1042
  var CHECKING_WALLET_AVAILABILITY = {
621
1043
  status: "checking",
622
1044
  isAuthorized: false,
@@ -629,6 +1051,17 @@ var CHECKING_WALLET_AVAILABILITY = {
629
1051
  metadata: null,
630
1052
  error: null
631
1053
  };
1054
+ function completeAppMetadata(metadata) {
1055
+ if (!metadata?.appId || !metadata.appName || !metadata.appUrl) {
1056
+ return void 0;
1057
+ }
1058
+ return {
1059
+ appId: metadata.appId,
1060
+ appName: metadata.appName,
1061
+ appUrl: metadata.appUrl,
1062
+ ...metadata.imageUrl ? { imageUrl: metadata.imageUrl } : {}
1063
+ };
1064
+ }
632
1065
  var NativeSDK = class {
633
1066
  constructor(config = {}) {
634
1067
  this.eventListeners = /* @__PURE__ */ new Map();
@@ -647,10 +1080,25 @@ var NativeSDK = class {
647
1080
  this.storageKey = config.storageKey ?? DEFAULT_STORAGE_KEY;
648
1081
  this.selectedAccountStorageKey = config.selectedAccountStorageKey ?? `${this.storageKey}${SELECTED_ACCOUNT_STORAGE_KEY_SUFFIX}`;
649
1082
  this.iosWebViewMode = config.iosWebViewMode ?? "shell-iframe";
1083
+ this.walletExperience = config.walletExperience ?? "standard";
1084
+ this.defaultMetadata = config.metadata;
1085
+ const walletUrl = config.walletUrl ?? (this.walletExperience === "transparent" ? DEFAULT_TRANSPARENT_WALLET_URL : DEFAULT_NATIVE_WALLET_URL);
1086
+ const walletOrigin = new URL(walletUrl).origin;
1087
+ const signingSessions = this.storage ? new SigningSessionDescriptorStore(
1088
+ this.storage,
1089
+ resolveSigningSessionStorageKey({
1090
+ walletOrigin,
1091
+ appOrigin: this.origin,
1092
+ storageKey: config.signingSessionStorageKey ?? `${this.storageKey}${SIGNING_SESSION_STORAGE_KEY_SUFFIX}`
1093
+ })
1094
+ ) : void 0;
650
1095
  this.provider = new NativeProvider({
651
- walletUrl: config.walletUrl,
1096
+ walletUrl,
652
1097
  origin: this.origin,
653
- addressTypes: config.addressTypes ?? [AddressType.THRU]
1098
+ metadata: this.defaultMetadata ? this.resolveMetadata(this.defaultMetadata) : void 0,
1099
+ addressTypes: config.addressTypes ?? [AddressType.THRU],
1100
+ signingSessions,
1101
+ walletExperience: this.walletExperience
654
1102
  });
655
1103
  this.setupEventForwarding();
656
1104
  }
@@ -701,10 +1149,10 @@ var NativeSDK = class {
701
1149
  this.emit("connect", { status: "connecting" });
702
1150
  const inFlight = (async () => {
703
1151
  try {
704
- this.provider.requestShow();
1152
+ await this.provider.requestShow();
705
1153
  if (!this.initialized) await this.initialize();
706
1154
  const metadata = this.resolveMetadata(options?.metadata);
707
- const preferredAccountAddress = isAccountSwitch ? null : await this.readSelectedAccountAddress();
1155
+ const preferredAccountAddress = isAccountSwitch ? null : options?.preferredAccountAddress ?? await this.readSelectedAccountAddress();
708
1156
  const providerOptions = metadata || preferredAccountAddress || options?.intent ? {
709
1157
  ...metadata ? { metadata } : {},
710
1158
  ...preferredAccountAddress ? { preferredAccountAddress } : {},
@@ -757,11 +1205,52 @@ var NativeSDK = class {
757
1205
  ...options.intent ? { intent: options.intent } : {}
758
1206
  });
759
1207
  }
1208
+ async createAccount(options = {}) {
1209
+ this.emit("connect", { status: "connecting" });
1210
+ try {
1211
+ await this.provider.requestShow();
1212
+ if (!this.initialized) await this.initialize();
1213
+ const metadata = this.resolveMetadata(options.metadata);
1214
+ const result = await this.provider.createAccount({
1215
+ ...options.accountName ? { accountName: options.accountName } : {},
1216
+ ...metadata ? { metadata } : {}
1217
+ });
1218
+ const selectedAccount = result.selectedAccount ?? result.account;
1219
+ const activeResult = {
1220
+ ...result,
1221
+ accounts: this.provider.getAccounts(),
1222
+ selectedAccount,
1223
+ account: selectedAccount
1224
+ };
1225
+ const completedResult = {
1226
+ accounts: activeResult.accounts,
1227
+ selectedAccount: activeResult.selectedAccount,
1228
+ status: "completed",
1229
+ metadata: completeAppMetadata(metadata)
1230
+ };
1231
+ this.lastConnectResult = completedResult;
1232
+ await this.persistSelectedAccountAddress(
1233
+ activeResult.selectedAccount.address
1234
+ );
1235
+ await this.clearPersistedConnection();
1236
+ this.setWalletAvailability(
1237
+ walletAvailabilityFromConnectResult(completedResult)
1238
+ );
1239
+ this.emit("connect", completedResult);
1240
+ this.emit("accountChanged", activeResult.selectedAccount);
1241
+ return activeResult;
1242
+ } catch (error) {
1243
+ this.provider.requestHide();
1244
+ this.emit("error", error);
1245
+ throw error;
1246
+ }
1247
+ }
760
1248
  async disconnect() {
761
1249
  try {
762
1250
  await this.provider.disconnect();
763
1251
  this.emit("disconnect", {});
764
1252
  this.lastConnectResult = null;
1253
+ await this.persistSelectedAccountAddress(null);
765
1254
  await this.clearPersistedConnection();
766
1255
  this.clearAuthorizedAvailability();
767
1256
  } catch (error) {
@@ -906,9 +1395,9 @@ var NativeSDK = class {
906
1395
  }
907
1396
  async requestConnectionState(options) {
908
1397
  if (!this.initialized) await this.initialize();
909
- const metadata = options?.metadata ?? this.lastConnectResult?.metadata ?? void 0;
1398
+ const metadata = options?.metadata ?? this.lastConnectResult?.metadata ?? this.defaultMetadata ?? void 0;
910
1399
  const providerOptions = metadata ? { metadata: this.resolveMetadata(metadata) } : void 0;
911
- const preferredAccountAddress = await this.readSelectedAccountAddress();
1400
+ const preferredAccountAddress = options?.preferredAccountAddress ?? await this.readSelectedAccountAddress();
912
1401
  const nextProviderOptions = providerOptions || preferredAccountAddress ? {
913
1402
  ...providerOptions ?? {},
914
1403
  ...preferredAccountAddress ? { preferredAccountAddress } : {}
@@ -961,15 +1450,16 @@ var NativeSDK = class {
961
1450
  });
962
1451
  }
963
1452
  resolveMetadata(input) {
964
- if (!input) {
1453
+ const effectiveInput = input ?? this.defaultMetadata;
1454
+ if (!effectiveInput) {
965
1455
  return { appId: this.origin };
966
1456
  }
967
1457
  const metadata = {
968
- appId: input.appId ?? this.origin
1458
+ appId: effectiveInput.appId ?? this.origin
969
1459
  };
970
- if (input.appUrl) metadata.appUrl = input.appUrl;
971
- if (input.appName) metadata.appName = input.appName;
972
- if (input.imageUrl) metadata.imageUrl = input.imageUrl;
1460
+ if (effectiveInput.appUrl) metadata.appUrl = effectiveInput.appUrl;
1461
+ if (effectiveInput.appName) metadata.appName = effectiveInput.appName;
1462
+ if (effectiveInput.imageUrl) metadata.imageUrl = effectiveInput.imageUrl;
973
1463
  return metadata;
974
1464
  }
975
1465
  resolveSignInMetadata(options) {
@@ -1230,6 +1720,27 @@ function ThruProvider({ children, config }) {
1230
1720
  throw err;
1231
1721
  }
1232
1722
  }, [sdk]);
1723
+ const createAccount = useCallback(
1724
+ async (options) => {
1725
+ if (!sdk) throw new Error("NativeSDK not initialized");
1726
+ try {
1727
+ const result = await sdk.createAccount(options);
1728
+ setSelectedAccount(result.selectedAccount);
1729
+ setAccounts(result.accounts);
1730
+ setIsConnected(true);
1731
+ setIsConnecting(false);
1732
+ setWalletAvailability(sdk.getWalletAvailability());
1733
+ return result;
1734
+ } catch (err) {
1735
+ setError(
1736
+ err instanceof Error ? err : new Error("createAccount failed")
1737
+ );
1738
+ setIsConnecting(false);
1739
+ throw err;
1740
+ }
1741
+ },
1742
+ [sdk]
1743
+ );
1233
1744
  return /* @__PURE__ */ jsx(
1234
1745
  ThruContext.Provider,
1235
1746
  {
@@ -1243,6 +1754,7 @@ function ThruProvider({ children, config }) {
1243
1754
  selectedAccount,
1244
1755
  walletAvailability,
1245
1756
  selectAccount,
1757
+ createAccount,
1246
1758
  manageAccounts
1247
1759
  },
1248
1760
  children
@@ -2266,6 +2778,219 @@ var styles = StyleSheet.create({
2266
2778
  },
2267
2779
  webview: { flex: 1, backgroundColor: "transparent" }
2268
2780
  });
2781
+ function ThruTransparentWalletBridge({
2782
+ wallet: walletProp,
2783
+ style,
2784
+ webViewProps
2785
+ }) {
2786
+ const thruContext = useContext(ThruContext);
2787
+ const wallet = walletProp ?? thruContext?.wallet ?? null;
2788
+ const webViewRef = useRef(null);
2789
+ const webViewNativeTagRef = useRef(null);
2790
+ const didRefreshWalletAvailabilityRef = useRef(false);
2791
+ const [isFocusSurfaceActive, setIsFocusSurfaceActive] = useState(false);
2792
+ const attachIfReady = useCallback(() => {
2793
+ if (!wallet || !webViewRef.current) return;
2794
+ const ref = {
2795
+ injectJavaScript: (script) => {
2796
+ webViewRef.current?.injectJavaScript(script);
2797
+ }
2798
+ };
2799
+ wallet.attachWebView(ref);
2800
+ }, [wallet]);
2801
+ const enableAndroidWebAuthnIfNeeded = useCallback(async () => {
2802
+ if (Platform.OS !== "android") return false;
2803
+ const enabled = await enableWebAuthnSupport(webViewNativeTagRef.current);
2804
+ webViewRef.current?.injectJavaScript(
2805
+ "window.dispatchEvent(new Event('thru:native-webauthn-ready')); true;"
2806
+ );
2807
+ return enabled;
2808
+ }, []);
2809
+ const focusWebViewDocument = useCallback(() => {
2810
+ const webView = webViewRef.current;
2811
+ webView?.requestFocus?.();
2812
+ webViewRef.current?.injectJavaScript(
2813
+ "try { window.focus(); document.body && document.body.focus && document.body.focus(); } catch (_) {} true;"
2814
+ );
2815
+ }, []);
2816
+ const refreshWalletAvailabilityIfReady = useCallback(() => {
2817
+ if (!wallet || didRefreshWalletAvailabilityRef.current) return;
2818
+ didRefreshWalletAvailabilityRef.current = true;
2819
+ void wallet.refreshWalletAvailability();
2820
+ }, [wallet]);
2821
+ useEffect(() => {
2822
+ if (!wallet) return;
2823
+ wallet.setUiHandlers({
2824
+ onShowRequested: () => {
2825
+ setIsFocusSurfaceActive(true);
2826
+ },
2827
+ onHideRequested: () => {
2828
+ setIsFocusSurfaceActive(false);
2829
+ }
2830
+ });
2831
+ return () => {
2832
+ wallet.clearUiHandlers();
2833
+ };
2834
+ }, [focusWebViewDocument, wallet]);
2835
+ useEffect(() => {
2836
+ if (!isFocusSurfaceActive) return;
2837
+ const timers = [0, 50, 120, 250, 500].map(
2838
+ (delay) => setTimeout(focusWebViewDocument, delay)
2839
+ );
2840
+ return () => {
2841
+ timers.forEach(clearTimeout);
2842
+ };
2843
+ }, [focusWebViewDocument, isFocusSurfaceActive]);
2844
+ const webViewSource = useMemo(() => {
2845
+ if (!wallet) return null;
2846
+ if (Platform.OS === "ios" && wallet.getIosWebViewMode() === "direct") {
2847
+ return { uri: wallet.getIframeSrc() };
2848
+ }
2849
+ return {
2850
+ html: getShellHtml({
2851
+ walletUrl: wallet.getIframeSrc(),
2852
+ walletOrigin: wallet.getWalletOrigin()
2853
+ }),
2854
+ baseUrl: wallet.getWalletOrigin()
2855
+ };
2856
+ }, [wallet]);
2857
+ const isDirectWalletSource = Boolean(
2858
+ wallet && Platform.OS === "ios" && wallet.getIosWebViewMode() === "direct"
2859
+ );
2860
+ useEffect(() => {
2861
+ didRefreshWalletAvailabilityRef.current = false;
2862
+ }, [webViewSource]);
2863
+ const handleWebViewLayout = useCallback(
2864
+ (event) => {
2865
+ const target = event.nativeEvent.target;
2866
+ webViewNativeTagRef.current = typeof target === "number" ? target : webViewNativeTagRef.current;
2867
+ void enableAndroidWebAuthnIfNeeded();
2868
+ webViewProps?.onLayout?.(event);
2869
+ },
2870
+ [enableAndroidWebAuthnIfNeeded, webViewProps]
2871
+ );
2872
+ const handleLoadEnd = useCallback(
2873
+ (event) => {
2874
+ attachIfReady();
2875
+ if (isDirectWalletSource) {
2876
+ void enableAndroidWebAuthnIfNeeded().finally(
2877
+ refreshWalletAvailabilityIfReady
2878
+ );
2879
+ } else {
2880
+ void enableAndroidWebAuthnIfNeeded();
2881
+ }
2882
+ webViewProps?.onLoadEnd?.(event);
2883
+ },
2884
+ [
2885
+ attachIfReady,
2886
+ enableAndroidWebAuthnIfNeeded,
2887
+ isDirectWalletSource,
2888
+ refreshWalletAvailabilityIfReady,
2889
+ webViewProps
2890
+ ]
2891
+ );
2892
+ const handleMessage = useCallback(
2893
+ (event) => {
2894
+ let shouldRefreshAfterBridgeReady = false;
2895
+ let shouldCollapseFocusSurface = false;
2896
+ try {
2897
+ const data = JSON.parse(event.nativeEvent.data);
2898
+ shouldRefreshAfterBridgeReady = data.type === "iframe:ready";
2899
+ shouldCollapseFocusSurface = typeof data.id === "string" && typeof data.success === "boolean";
2900
+ } catch {
2901
+ }
2902
+ if (shouldCollapseFocusSurface) {
2903
+ setIsFocusSurfaceActive(false);
2904
+ }
2905
+ wallet?.onMessage({
2906
+ nativeEvent: { data: event.nativeEvent.data }
2907
+ });
2908
+ webViewProps?.onMessage?.(event);
2909
+ if (shouldRefreshAfterBridgeReady) {
2910
+ void enableAndroidWebAuthnIfNeeded().finally(
2911
+ refreshWalletAvailabilityIfReady
2912
+ );
2913
+ }
2914
+ },
2915
+ [
2916
+ enableAndroidWebAuthnIfNeeded,
2917
+ refreshWalletAvailabilityIfReady,
2918
+ wallet,
2919
+ webViewProps
2920
+ ]
2921
+ );
2922
+ if (!webViewSource) return null;
2923
+ return /* @__PURE__ */ jsx(
2924
+ View,
2925
+ {
2926
+ collapsable: false,
2927
+ pointerEvents: isFocusSurfaceActive ? "auto" : "none",
2928
+ style: [
2929
+ styles2.container,
2930
+ isFocusSurfaceActive ? styles2.activeContainer : null,
2931
+ style
2932
+ ],
2933
+ children: /* @__PURE__ */ jsx(
2934
+ WebView,
2935
+ {
2936
+ ...webViewProps,
2937
+ ref: webViewRef,
2938
+ source: webViewSource,
2939
+ originWhitelist: ["*"],
2940
+ javaScriptEnabled: true,
2941
+ domStorageEnabled: true,
2942
+ webviewDebuggingEnabled: __DEV__,
2943
+ sharedCookiesEnabled: true,
2944
+ allowsInlineMediaPlayback: true,
2945
+ mediaPlaybackRequiresUserAction: false,
2946
+ limitsNavigationsToAppBoundDomains: isDirectWalletSource,
2947
+ onLoadStart: (event) => {
2948
+ attachIfReady();
2949
+ void enableAndroidWebAuthnIfNeeded();
2950
+ webViewProps?.onLoadStart?.(event);
2951
+ },
2952
+ onLoadEnd: handleLoadEnd,
2953
+ onLayout: handleWebViewLayout,
2954
+ onMessage: handleMessage,
2955
+ style: [
2956
+ styles2.webview,
2957
+ isFocusSurfaceActive ? styles2.activeWebview : null,
2958
+ webViewProps?.style
2959
+ ]
2960
+ }
2961
+ )
2962
+ }
2963
+ );
2964
+ }
2965
+ var styles2 = StyleSheet.create({
2966
+ container: {
2967
+ height: 1,
2968
+ left: 0,
2969
+ opacity: 0,
2970
+ overflow: "hidden",
2971
+ position: "absolute",
2972
+ top: 0,
2973
+ width: 1
2974
+ },
2975
+ activeContainer: {
2976
+ bottom: 0,
2977
+ height: "100%",
2978
+ opacity: 1,
2979
+ right: 0,
2980
+ width: "100%",
2981
+ zIndex: 2147483647
2982
+ },
2983
+ webview: {
2984
+ backgroundColor: "transparent",
2985
+ height: 1,
2986
+ width: 1
2987
+ },
2988
+ activeWebview: {
2989
+ flex: 1,
2990
+ height: "100%",
2991
+ width: "100%"
2992
+ }
2993
+ });
2269
2994
 
2270
2995
  // src/native/react/hooks/waitForWallet.ts
2271
2996
  function waitForWallet(getWallet, timeout = 5e3, interval = 100) {
@@ -2307,6 +3032,13 @@ function useWallet() {
2307
3032
  const ready = walletRef.current ?? await waitForWallet(() => walletRef.current);
2308
3033
  return ready.signIn(options);
2309
3034
  }, []);
3035
+ const createTransparentAccount = useCallback(
3036
+ async (options) => {
3037
+ const ready = walletRef.current ?? await waitForWallet(() => walletRef.current);
3038
+ return ready.createAccount(options);
3039
+ },
3040
+ []
3041
+ );
2310
3042
  const disconnect = useCallback(async () => {
2311
3043
  const ready = walletRef.current ?? await waitForWallet(() => walletRef.current);
2312
3044
  await ready.disconnect();
@@ -2321,6 +3053,7 @@ function useWallet() {
2321
3053
  accounts,
2322
3054
  connect,
2323
3055
  signIn,
3056
+ createAccount: createTransparentAccount,
2324
3057
  disconnect,
2325
3058
  isConnected: isConnected && !!wallet,
2326
3059
  isConnecting,
@@ -2376,6 +3109,6 @@ function useAccounts({ onAccountSelect } = {}) {
2376
3109
  };
2377
3110
  }
2378
3111
 
2379
- export { ThruContext, ThruProvider, ThruWalletSheet, enableWebAuthnSupport, useAccounts, useThru, useWallet, useWalletAvailability };
3112
+ export { ThruContext, ThruProvider, ThruTransparentWalletBridge, ThruWalletSheet, enableWebAuthnSupport, useAccounts, useThru, useWallet, useWalletAvailability };
2380
3113
  //# sourceMappingURL=react.js.map
2381
3114
  //# sourceMappingURL=react.js.map