@thru/wallet 0.2.28 → 0.2.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thru/wallet",
3
- "version": "0.2.28",
3
+ "version": "0.2.30",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -46,7 +46,7 @@
46
46
  "README.md"
47
47
  ],
48
48
  "dependencies": {
49
- "@thru/sdk": "0.2.28"
49
+ "@thru/sdk": "0.2.30"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@svgr/core": "^8.1.0",
@@ -159,7 +159,7 @@ describe("NativeSDK", () => {
159
159
  });
160
160
  const iframeUrl = new URL(transparentSdk.getIframeSrc());
161
161
 
162
- expect(iframeUrl.origin).toBe("https://wallet.thru.org");
162
+ expect(iframeUrl.origin).toBe("https://app.tid.sh");
163
163
  expect(iframeUrl.pathname).toBe("/embedded/native/transparent");
164
164
 
165
165
  transparentSdk.destroy();
@@ -295,6 +295,93 @@ describe("NativeSDK", () => {
295
295
  });
296
296
  });
297
297
 
298
+ it("persists a bundled transparent createAccount signing session", async () => {
299
+ sdk.destroy();
300
+ const storage = new MockStorage();
301
+ sdk = new NativeSDK({
302
+ walletUrl: "http://localhost:3000/embedded/native/transparent",
303
+ walletExperience: "transparent",
304
+ origin: "thru-mobile://token-dummy",
305
+ storage,
306
+ });
307
+ webView = new MockWebView();
308
+ sdk.attachWebView(webView);
309
+ const nowSeconds = 1_800_000_000;
310
+
311
+ const frameId = frameIdFor(sdk);
312
+ const promise = sdk.createAccount({
313
+ accountName: "JCoin Account",
314
+ metadata: {
315
+ appId: "token_dummy_app",
316
+ appName: "Token Dummy App",
317
+ appUrl: "thru-mobile://token-dummy",
318
+ },
319
+ createSigningSession: { expiresAt: nowSeconds + 120 },
320
+ });
321
+
322
+ sdk.onMessage(readyMessage(frameId));
323
+ await flush();
324
+
325
+ const request = parseInjectedRequest(await waitForInjectedRequest(webView));
326
+ expect(request.type).toBe(POST_MESSAGE_REQUEST_TYPES.CREATE_ACCOUNT);
327
+ expect(request.payload).toEqual({
328
+ accountName: "JCoin Account",
329
+ metadata: {
330
+ appId: "token_dummy_app",
331
+ appName: "Token Dummy App",
332
+ appUrl: "thru-mobile://token-dummy",
333
+ },
334
+ createSigningSession: {
335
+ expiresAt: String(nowSeconds + 120),
336
+ },
337
+ });
338
+
339
+ const result = {
340
+ account: {
341
+ accountType: "thru",
342
+ address: "thru_created_address",
343
+ label: "JCoin Account",
344
+ },
345
+ accounts: [
346
+ {
347
+ accountType: "thru",
348
+ address: "thru_created_address",
349
+ label: "JCoin Account",
350
+ },
351
+ ],
352
+ selectedAccount: {
353
+ accountType: "thru",
354
+ address: "thru_created_address",
355
+ label: "JCoin Account",
356
+ },
357
+ signature: "thru_signature",
358
+ vmError: "0",
359
+ userErrorCode: "0",
360
+ executionResult: "0",
361
+ signingSession: {
362
+ id: "session_1",
363
+ walletAddress: "thru_created_address",
364
+ publicKey: "thru_session_address",
365
+ authIdx: 1,
366
+ expiresAt: String(nowSeconds + 120),
367
+ createdAt: String(nowSeconds),
368
+ },
369
+ };
370
+ sdk.onMessage(responseMessage(frameId, request.id, result));
371
+
372
+ await expect(promise).resolves.toEqual(result);
373
+ await expect(sdk.thru.getSigningSessions()).resolves.toEqual([
374
+ expect.objectContaining({
375
+ id: "session_1",
376
+ walletAddress: "thru_created_address",
377
+ publicKey: "thru_session_address",
378
+ authIdx: 1,
379
+ expiresAt: nowSeconds + 120,
380
+ createdAt: nowSeconds,
381
+ }),
382
+ ]);
383
+ });
384
+
298
385
  it("sends transparent passkey challenge signing requests through the wallet WebView", async () => {
299
386
  sdk.destroy();
300
387
  sdk = new NativeSDK({
@@ -4,6 +4,8 @@ import {
4
4
  type AddressType as AddressTypeValue,
5
5
  type ConnectResult,
6
6
  type IThruChain,
7
+ type ThruSigningSessionCreateOptions,
8
+ type ThruSigningSessionDescriptor,
7
9
  type WalletAccount,
8
10
  normalizeActiveWalletAccounts,
9
11
  normalizeWalletAccountResult,
@@ -16,6 +18,7 @@ import {
16
18
  type CreateAccountResult,
17
19
  type GetConnectionStateResult,
18
20
  type ManageAccountsResult,
21
+ type SigningSessionDescriptorPayload,
19
22
  normalizeConnectionStateResult,
20
23
  } from "../protocol";
21
24
  import { NativeProvider } from "./provider/NativeProvider";
@@ -113,6 +116,7 @@ export interface ConnectOptions {
113
116
  export interface CreateAccountOptions {
114
117
  accountName?: string;
115
118
  metadata?: ConnectMetadataInput;
119
+ createSigningSession?: Omit<ThruSigningSessionCreateOptions, "walletAddress" | "review">;
116
120
  }
117
121
 
118
122
  export interface RestoreConnectionOptions {
@@ -144,9 +148,9 @@ export interface NativeSDKUiHandlers {
144
148
  const DEFAULT_STORAGE_KEY = "thru.native-sdk.connection.v1";
145
149
  const SELECTED_ACCOUNT_STORAGE_KEY_SUFFIX = ".selected-account.v1";
146
150
  const SIGNING_SESSION_STORAGE_KEY_SUFFIX = ".signing-sessions.v1";
147
- const DEFAULT_NATIVE_WALLET_URL = "https://wallet.thru.org/embedded/native";
151
+ const DEFAULT_NATIVE_WALLET_URL = "https://app.tid.sh/embedded/native";
148
152
  const DEFAULT_TRANSPARENT_WALLET_URL =
149
- "https://wallet.thru.org/embedded/native/transparent";
153
+ "https://app.tid.sh/embedded/native/transparent";
150
154
 
151
155
  const CHECKING_WALLET_AVAILABILITY: WalletAvailability = {
152
156
  status: "checking",
@@ -175,6 +179,19 @@ function completeAppMetadata(
175
179
  };
176
180
  }
177
181
 
182
+ function signingSessionDescriptorFromWire(
183
+ session: SigningSessionDescriptorPayload,
184
+ ): ThruSigningSessionDescriptor {
185
+ return {
186
+ id: session.id,
187
+ walletAddress: session.walletAddress,
188
+ publicKey: session.publicKey,
189
+ authIdx: session.authIdx,
190
+ expiresAt: Number(BigInt(session.expiresAt)),
191
+ createdAt: Number(BigInt(session.createdAt)),
192
+ };
193
+ }
194
+
178
195
  interface PersistedSelectedAccountSnapshot {
179
196
  version: 1;
180
197
  origin: string;
@@ -205,6 +222,7 @@ export class NativeSDK {
205
222
  private readonly iosWebViewMode: IosWebViewMode;
206
223
  private readonly walletExperience: NativeWalletExperience;
207
224
  private readonly defaultMetadata?: ConnectMetadataInput;
225
+ private readonly signingSessions?: SigningSessionDescriptorStore;
208
226
 
209
227
  constructor(config: NativeSDKConfig = {}) {
210
228
  this.origin = config.origin ?? "thru-mobile://app";
@@ -235,6 +253,7 @@ export class NativeSDK {
235
253
  }),
236
254
  )
237
255
  : undefined;
256
+ this.signingSessions = signingSessions;
238
257
  this.provider = new NativeProvider({
239
258
  walletUrl,
240
259
  origin: this.origin,
@@ -268,7 +287,7 @@ export class NativeSDK {
268
287
  return this.provider.getIframeSrc();
269
288
  }
270
289
 
271
- /** Wallet origin (e.g. https://wallet.thru.org). */
290
+ /** Wallet origin (e.g. https://app.tid.sh). */
272
291
  getWalletOrigin(): string {
273
292
  return this.provider.getWalletOrigin();
274
293
  }
@@ -394,6 +413,9 @@ export class NativeSDK {
394
413
  const result = await this.provider.createAccount({
395
414
  ...(options.accountName ? { accountName: options.accountName } : {}),
396
415
  ...(metadata ? { metadata } : {}),
416
+ ...(options.createSigningSession
417
+ ? { createSigningSession: options.createSigningSession }
418
+ : {}),
397
419
  });
398
420
  const selectedAccount = result.selectedAccount ?? result.account;
399
421
  const activeResult: CreateAccountResult = {
@@ -412,6 +434,14 @@ export class NativeSDK {
412
434
  await this.persistSelectedAccountAddress(
413
435
  activeResult.selectedAccount.address,
414
436
  );
437
+ if (activeResult.signingSession) {
438
+ if (!this.signingSessions) {
439
+ throw new Error("NativeSDKStorage is required for signing sessions");
440
+ }
441
+ await this.signingSessions.saveReplacingWalletSessions(
442
+ signingSessionDescriptorFromWire(activeResult.signingSession),
443
+ );
444
+ }
415
445
  await this.clearPersistedConnection();
416
446
  this.setWalletAvailability(
417
447
  walletAvailabilityFromConnectResult(completedResult),
@@ -28,13 +28,15 @@ import {
28
28
  type WebViewMessageEventLike,
29
29
  type WebViewRefLike,
30
30
  } from "./WebViewBridge";
31
+ import { resolveSessionExpirySeconds } from "../../signing-sessions";
32
+ import type { ThruSigningSessionCreateOptions } from "../../interfaces";
31
33
 
32
- const DEFAULT_WALLET_URL = "https://wallet.thru.org/embedded/native";
34
+ const DEFAULT_WALLET_URL = "https://app.tid.sh/embedded/native";
33
35
  const DEFAULT_ORIGIN = "thru-mobile://app";
34
36
  const TRANSPARENT_FOCUS_SETTLE_MS = 500;
35
37
 
36
38
  export interface NativeProviderConfig {
37
- /** wallet.thru.org/embedded/native URL to load. */
39
+ /** app.tid.sh/embedded/native URL to load. */
38
40
  walletUrl?: string;
39
41
  /** Standard bottom-sheet wallet or transparent auto-signing wallet. */
40
42
  walletExperience?: "standard" | "transparent";
@@ -56,6 +58,7 @@ export interface ConnectOptions {
56
58
  export interface CreateAccountOptions {
57
59
  accountName?: string;
58
60
  metadata?: ConnectMetadataInput;
61
+ createSigningSession?: Omit<ThruSigningSessionCreateOptions, "walletAddress" | "review">;
59
62
  }
60
63
 
61
64
  export type NativeProviderEvent = EmbeddedProviderEvent;
@@ -153,7 +156,7 @@ export class NativeProvider {
153
156
  return this.bridge.getIframeSrc();
154
157
  }
155
158
 
156
- /** Wallet origin (e.g. https://wallet.thru.org). The shell template
159
+ /** Wallet origin (e.g. https://app.tid.sh). The shell template
157
160
  should substitute this for WALLET_ORIGIN_PLACEHOLDER. */
158
161
  getWalletOrigin(): string {
159
162
  return this.bridge.walletOrigin;
@@ -238,6 +241,11 @@ export class NativeProvider {
238
241
  const payload: CreateAccountPayload = {};
239
242
  if (options?.accountName) payload.accountName = options.accountName;
240
243
  if (options?.metadata) payload.metadata = options.metadata;
244
+ if (options?.createSigningSession) {
245
+ payload.createSigningSession = {
246
+ expiresAt: String(resolveSessionExpirySeconds(options.createSigningSession)),
247
+ };
248
+ }
241
249
 
242
250
  const response = await this.bridge.sendMessage({
243
251
  id: createRequestId(),
@@ -154,9 +154,9 @@ describe('WebViewBridge', () => {
154
154
  process.env.NODE_ENV = 'production';
155
155
 
156
156
  const productionBridge = new WebViewBridge({
157
- walletUrl: 'https://wallet.thru.org/embedded',
157
+ walletUrl: 'https://app.tid.sh/embedded',
158
158
  });
159
- expect(productionBridge.walletOrigin).toBe('https://wallet.thru.org');
159
+ expect(productionBridge.walletOrigin).toBe('https://app.tid.sh');
160
160
  productionBridge.destroy();
161
161
 
162
162
  expect(
@@ -12,12 +12,12 @@ import {
12
12
 
13
13
  /* RN-side analog of `web/packages/embedded-provider/src/IframeManager.ts`.
14
14
  The wallet ships unchanged. The shell HTML (src/shell.html) hosts an
15
- <iframe src="wallet.thru.org/embedded/native"> and forwards
15
+ <iframe src="app.tid.sh/embedded/native"> and forwards
16
16
  iframe<->ReactNativeWebView postMessage traffic. This bridge only
17
17
  speaks the RN side: webView.injectJavaScript out, onMessage in. */
18
18
 
19
19
  const PRODUCTION_WALLET_ORIGINS = [
20
- 'https://wallet.thru.org',
20
+ 'https://app.tid.sh',
21
21
  'https://wallet.tid.sh',
22
22
  ];
23
23
 
@@ -6,8 +6,8 @@ import { getShellHtml } from './shell';
6
6
 
7
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
8
  const TEST_SHELL_OPTIONS = {
9
- walletUrl: 'https://wallet.thru.org/embedded?tn_frame_id=frame_test',
10
- walletOrigin: 'https://wallet.thru.org',
9
+ walletUrl: 'https://app.tid.sh/embedded?tn_frame_id=frame_test',
10
+ walletOrigin: 'https://app.tid.sh',
11
11
  };
12
12
 
13
13
  describe('native shell HTML', () => {
@@ -36,7 +36,7 @@ describe('native shell HTML', () => {
36
36
 
37
37
  it('substitutes shell placeholders without reprocessing inserted values', () => {
38
38
  const walletUrl =
39
- 'https://wallet.thru.org/embedded?marker=WALLET_ORIGIN_PLACEHOLDER';
39
+ 'https://app.tid.sh/embedded?marker=WALLET_ORIGIN_PLACEHOLDER';
40
40
  const walletOrigin = 'thru-mobile://WALLET_URL_PLACEHOLDER/$&';
41
41
 
42
42
  const html = getShellHtml({ walletUrl, walletOrigin });
@@ -95,7 +95,7 @@ export interface ShellOptions {
95
95
  }
96
96
 
97
97
  /**
98
- * Returns the shell HTML for loading wallet.thru.org/embedded inside a
98
+ * Returns the shell HTML for loading app.tid.sh/embedded inside a
99
99
  * react-native-webview. The shell hosts an <iframe> pointing at the wallet
100
100
  * and bridges window.postMessage traffic between the iframe and the
101
101
  * react-native-webview's onMessage / injectJavaScript channels.
@@ -157,6 +157,9 @@ export interface DisconnectResult {
157
157
  export interface CreateAccountPayload {
158
158
  accountName?: string;
159
159
  metadata?: ConnectMetadataInput;
160
+ createSigningSession?: {
161
+ expiresAt: string;
162
+ };
160
163
  }
161
164
 
162
165
  export interface CreateAccountResult {
@@ -167,6 +170,7 @@ export interface CreateAccountResult {
167
170
  vmError: string | null;
168
171
  userErrorCode: string | null;
169
172
  executionResult: string | null;
173
+ signingSession?: SigningSessionDescriptorPayload;
170
174
  }
171
175
 
172
176
  export interface GetAccountsResult {
@@ -3,7 +3,7 @@ import { IframeManager } from './IframeManager';
3
3
 
4
4
  describe('IframeManager', () => {
5
5
  it('allows trusted production wallet origins', () => {
6
- const thruBridge = new IframeManager('https://wallet.thru.org/embedded');
6
+ const thruBridge = new IframeManager('https://app.tid.sh/embedded');
7
7
  const tidBridge = new IframeManager('https://wallet.tid.sh/embedded');
8
8
 
9
9
  expect(thruBridge).toBeInstanceOf(IframeManager);
@@ -17,7 +17,7 @@ import {
17
17
  * origins so local HTTPS RP-ID testing can use the hosted wallet path.
18
18
  */
19
19
  const PRODUCTION_IFRAME_ORIGINS = [
20
- 'https://wallet.thru.org',
20
+ 'https://app.tid.sh',
21
21
  'https://wallet.tid.sh',
22
22
  ];
23
23