@thru/wallet 0.2.29 → 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.29",
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.29"
49
+ "@thru/sdk": "0.2.30"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@svgr/core": "^8.1.0",
@@ -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 {
@@ -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,
@@ -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,6 +28,8 @@ 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
34
  const DEFAULT_WALLET_URL = "https://app.tid.sh/embedded/native";
33
35
  const DEFAULT_ORIGIN = "thru-mobile://app";
@@ -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;
@@ -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(),
@@ -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 {