@chipi-stack/chipi-react 14.13.1 → 14.15.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.
package/dist/index.mjs CHANGED
@@ -193,6 +193,17 @@ function useGetWallet(input) {
193
193
  fetchWallet
194
194
  };
195
195
  }
196
+
197
+ // src/utils/wallet-capabilities.ts
198
+ var SHHH_SESSION_SIGNER_KINDS = /* @__PURE__ */ new Set(["STARK", "ED25519"]);
199
+ function walletSupportsSessions(wallet) {
200
+ if (!wallet) return false;
201
+ if (wallet.walletType === "CHIPI") return true;
202
+ if (wallet.walletType === "SHHH") {
203
+ return !wallet.signerKind || SHHH_SESSION_SIGNER_KINDS.has(wallet.signerKind);
204
+ }
205
+ return false;
206
+ }
196
207
  function useChipiWallet(config3) {
197
208
  const { chipiSDK } = useChipiContext();
198
209
  const queryClient = useQueryClient();
@@ -273,7 +284,7 @@ function useChipiWallet(config3) {
273
284
  const data = walletQuery.data;
274
285
  return {
275
286
  ...data,
276
- supportsSessionKeys: data.walletType === "CHIPI",
287
+ supportsSessionKeys: walletSupportsSessions(data),
277
288
  shortAddress: formatAddress(data.publicKey)
278
289
  };
279
290
  }, [walletQuery.data, walletQuery.isLoading]);
@@ -330,6 +341,7 @@ function useChipiSession(config3) {
330
341
  const {
331
342
  wallet,
332
343
  encryptKey,
344
+ getEncryptKey,
333
345
  getBearerToken,
334
346
  storedSession,
335
347
  onSessionCreated,
@@ -343,10 +355,13 @@ function useChipiSession(config3) {
343
355
  useEffect(() => {
344
356
  setLocalSession(storedSession ?? null);
345
357
  }, [storedSession]);
346
- const supportsSession = useMemo(() => {
347
- if (!wallet) return false;
348
- return wallet.walletType === "CHIPI";
349
- }, [wallet]);
358
+ const supportsSession = useMemo(() => walletSupportsSessions(wallet), [wallet]);
359
+ const resolveEncryptKey = useCallback(async () => {
360
+ const key = encryptKey || (getEncryptKey ? await getEncryptKey() : void 0);
361
+ if (!key) throw new Error("Encryption key (PIN) is required");
362
+ return key;
363
+ }, [encryptKey, getEncryptKey]);
364
+ const [awaitingRegistrationUntil, setAwaitingRegistrationUntil] = useState(null);
350
365
  const sessionStatusQuery = useQuery({
351
366
  queryKey: ["chipi-session-status", wallet?.publicKey, localSession?.publicKey],
352
367
  queryFn: async () => {
@@ -359,8 +374,12 @@ function useChipiSession(config3) {
359
374
  enabled: Boolean(
360
375
  autoCheckStatus && wallet?.publicKey && localSession?.publicKey && supportsSession
361
376
  ),
362
- staleTime: 3e4
377
+ staleTime: 3e4,
363
378
  // 30 seconds
379
+ // The registration hash comes back before the transaction is in a block, so
380
+ // right after registerSession the struct can still read as zero. Poll until
381
+ // it shows up (or for two minutes), then go back to on-demand reads.
382
+ refetchInterval: (query) => awaitingRegistrationUntil !== null && Date.now() < awaitingRegistrationUntil && (query.state.data?.validUntil ?? 0) === 0 ? 3e3 : false
364
383
  });
365
384
  const [revokedSessionKey, setRevokedSessionKey] = useState(null);
366
385
  const sessionState = useMemo(() => {
@@ -383,13 +402,13 @@ function useChipiSession(config3) {
383
402
  const createSessionMutation = useMutation(
384
403
  {
385
404
  mutationFn: async (params = {}) => {
386
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
387
405
  if (!supportsSession)
388
406
  throw new Error(
389
- "Wallet does not support sessions. Only CHIPI wallets support session keys."
407
+ "Wallet does not support sessions. Session keys need a CHIPI wallet or a SHHH wallet with a STARK / ED25519 signer."
390
408
  );
409
+ const key = await resolveEncryptKey();
391
410
  const sessionData = chipiSDK.sessions.createSessionKey({
392
- encryptKey,
411
+ encryptKey: key,
393
412
  durationSeconds: params.durationSeconds ?? defaultDurationSeconds
394
413
  });
395
414
  return sessionData;
@@ -409,29 +428,38 @@ function useChipiSession(config3) {
409
428
  const registerSessionMutation = useMutation({
410
429
  mutationFn: async (sessionConfig = {}) => {
411
430
  if (!wallet) throw new Error("Wallet is required");
412
- if (!localSession) throw new Error("No session to register. Call createSession first.");
413
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
431
+ const sessionPublicKey = sessionConfig.sessionPublicKey ?? localSession?.publicKey;
432
+ const validUntil = sessionConfig.validUntil ?? localSession?.validUntil;
433
+ if (!sessionPublicKey || validUntil === void 0)
434
+ throw new Error(
435
+ "No session to register. Call createSession first, or pass sessionPublicKey and validUntil."
436
+ );
414
437
  if (!supportsSession) throw new Error("Wallet does not support sessions");
438
+ const key = await resolveEncryptKey();
415
439
  const bearerToken = await getBearerToken();
416
440
  if (!bearerToken) throw new Error("Bearer token is required");
417
- const txHash = await chipiSDK.sessions.addSessionKeyToContract(
418
- {
419
- encryptKey,
420
- wallet,
421
- sessionConfig: {
422
- sessionPublicKey: localSession.publicKey,
423
- validUntil: sessionConfig.validUntil ?? localSession.validUntil,
424
- maxCalls: sessionConfig.maxCalls ?? defaultMaxCalls,
425
- allowedEntrypoints: sessionConfig.allowedEntrypoints ?? []
426
- }
427
- },
428
- bearerToken
429
- );
430
- return txHash;
441
+ const params = {
442
+ encryptKey: key,
443
+ wallet,
444
+ sessionConfig: {
445
+ sessionPublicKey,
446
+ validUntil,
447
+ maxCalls: sessionConfig.maxCalls ?? defaultMaxCalls,
448
+ allowedEntrypoints: sessionConfig.allowedEntrypoints ?? []
449
+ }
450
+ };
451
+ if (sessionConfig.spendingPolicies?.length) {
452
+ return chipiSDK.sessions.setupSession(
453
+ { ...params, spendingPolicies: sessionConfig.spendingPolicies },
454
+ bearerToken
455
+ );
456
+ }
457
+ return chipiSDK.sessions.addSessionKeyToContract(params, bearerToken);
431
458
  },
432
459
  onSuccess: () => {
433
460
  setError(null);
434
461
  if (localSession && revokedSessionKey === localSession.publicKey) setRevokedSessionKey(null);
462
+ setAwaitingRegistrationUntil(Date.now() + 12e4);
435
463
  queryClient.invalidateQueries({
436
464
  queryKey: ["chipi-session-status", wallet?.publicKey, localSession?.publicKey]
437
465
  });
@@ -441,26 +469,28 @@ function useChipiSession(config3) {
441
469
  }
442
470
  });
443
471
  const revokeSessionMutation = useMutation({
444
- mutationFn: async () => {
472
+ mutationFn: async (sessionPublicKey) => {
445
473
  if (!wallet) throw new Error("Wallet is required");
446
- if (!localSession) throw new Error("No session to revoke");
447
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
474
+ const target = sessionPublicKey ?? localSession?.publicKey;
475
+ if (!target) throw new Error("No session to revoke");
448
476
  if (!supportsSession) throw new Error("Wallet does not support sessions");
477
+ const key = await resolveEncryptKey();
449
478
  const bearerToken = await getBearerToken();
450
479
  if (!bearerToken) throw new Error("Bearer token is required");
451
480
  const txHash = await chipiSDK.sessions.revokeSessionKey(
452
481
  {
453
- encryptKey,
482
+ encryptKey: key,
454
483
  wallet,
455
- sessionPublicKey: localSession.publicKey
484
+ sessionPublicKey: target
456
485
  },
457
486
  bearerToken
458
487
  );
459
488
  return txHash;
460
489
  },
461
- onSuccess: () => {
490
+ onSuccess: (_txHash, sessionPublicKey) => {
462
491
  setError(null);
463
- if (localSession) setRevokedSessionKey(localSession.publicKey);
492
+ const target = sessionPublicKey ?? localSession?.publicKey;
493
+ if (target) setRevokedSessionKey(target);
464
494
  queryClient.invalidateQueries({
465
495
  queryKey: ["chipi-session-status", wallet?.publicKey, localSession?.publicKey]
466
496
  });
@@ -473,13 +503,13 @@ function useChipiSession(config3) {
473
503
  mutationFn: async (calls) => {
474
504
  if (!wallet) throw new Error("Wallet is required");
475
505
  if (!localSession) throw new Error("No active session");
476
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
477
506
  if (!hasActiveSession) throw new Error("Session is not active. Register the session first.");
507
+ const key = await resolveEncryptKey();
478
508
  const bearerToken = await getBearerToken();
479
509
  if (!bearerToken) throw new Error("Bearer token is required");
480
510
  const txHash = await chipiSDK.executeTransactionWithSession({
481
511
  params: {
482
- encryptKey,
512
+ encryptKey: key,
483
513
  wallet,
484
514
  session: localSession,
485
515
  calls
@@ -503,13 +533,13 @@ function useChipiSession(config3) {
503
533
  if (!wallet) throw new Error("Wallet is required");
504
534
  if (!localSession)
505
535
  throw new Error("No session to set policy on. Create and register a session first.");
506
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
507
536
  if (!supportsSession) throw new Error("Wallet does not support sessions");
537
+ const key = await resolveEncryptKey();
508
538
  const bearerToken = await getBearerToken();
509
539
  if (!bearerToken) throw new Error("Bearer token is required");
510
540
  const txHash = await chipiSDK.sessions.setSpendingPolicy(
511
541
  {
512
- encryptKey,
542
+ encryptKey: key,
513
543
  wallet,
514
544
  spendingPolicyConfig: {
515
545
  sessionPublicKey: localSession.publicKey,
@@ -531,13 +561,13 @@ function useChipiSession(config3) {
531
561
  mutationFn: async (token) => {
532
562
  if (!wallet) throw new Error("Wallet is required");
533
563
  if (!localSession) throw new Error("No session to remove policy from");
534
- if (!encryptKey) throw new Error("Encryption key (PIN) is required");
535
564
  if (!supportsSession) throw new Error("Wallet does not support sessions");
565
+ const key = await resolveEncryptKey();
536
566
  const bearerToken = await getBearerToken();
537
567
  if (!bearerToken) throw new Error("Bearer token is required");
538
568
  const txHash = await chipiSDK.sessions.removeSpendingPolicy(
539
569
  {
540
- encryptKey,
570
+ encryptKey: key,
541
571
  wallet,
542
572
  sessionPublicKey: localSession.publicKey,
543
573
  token
@@ -565,9 +595,14 @@ function useChipiSession(config3) {
565
595
  },
566
596
  [registerSessionMutation]
567
597
  );
568
- const revokeSession = useCallback(async () => {
569
- return revokeSessionMutation.mutateAsync();
570
- }, [revokeSessionMutation]);
598
+ const revokeSession = useCallback(
599
+ async (sessionPublicKey) => {
600
+ return revokeSessionMutation.mutateAsync(
601
+ typeof sessionPublicKey === "string" ? sessionPublicKey : void 0
602
+ );
603
+ },
604
+ [revokeSessionMutation]
605
+ );
571
606
  const executeWithSession = useCallback(
572
607
  async (calls) => {
573
608
  return executeWithSessionMutation.mutateAsync(calls);
@@ -21254,6 +21289,21 @@ function ChipiInjector({ children, ...config3 }) {
21254
21289
  }, [walletAddr]);
21255
21290
  return children ?? null;
21256
21291
  }
21292
+ var DEFAULT_RECOVER_LABELS = {
21293
+ proposeAddDevice: "Propose new device",
21294
+ proposeRecovery: "Initiate recovery",
21295
+ executeAddDevice: "Execute add-owner",
21296
+ executeRecovery: "Finalize recovery",
21297
+ timelockAddDevice: "48-hour timelock before this device becomes active.",
21298
+ timelockRecovery: "7-day timelock before the recovered wallet becomes active.",
21299
+ submitting: "Submitting\u2026",
21300
+ secondsRemaining: (s) => `${s}s remaining`,
21301
+ cancel: "Cancel pending op",
21302
+ timelockElapsed: "Timelock elapsed.",
21303
+ cancelling: "Cancelling\u2026",
21304
+ doneAddDevice: "New device added.",
21305
+ doneRecovery: "Wallet recovered."
21306
+ };
21257
21307
  function deriveStaticPhase(pendingOp, executed, isReady, nowSecs) {
21258
21308
  if (executed) return "done";
21259
21309
  if (!pendingOp) return "form-idle";
@@ -21335,10 +21385,17 @@ function Recover(props) {
21335
21385
  setSubmittingAction(null);
21336
21386
  }
21337
21387
  }, [activePendingOp, onCancel]);
21388
+ const L = useMemo(
21389
+ () => ({
21390
+ ...DEFAULT_RECOVER_LABELS,
21391
+ ...Object.fromEntries(Object.entries(props.labels ?? {}).filter(([, v]) => v !== void 0))
21392
+ }),
21393
+ [props.labels]
21394
+ );
21338
21395
  const isAddDevice = mode === "add-device";
21339
- const proposeLabel = isAddDevice ? "Propose new device" : "Initiate recovery";
21340
- const executeLabel = isAddDevice ? "Execute add-owner" : "Finalize recovery";
21341
- const timelockDescription = isAddDevice ? "48-hour timelock before this device becomes active." : "7-day timelock before the recovered wallet becomes active.";
21396
+ const proposeLabel = isAddDevice ? L.proposeAddDevice : L.proposeRecovery;
21397
+ const executeLabel = isAddDevice ? L.executeAddDevice : L.executeRecovery;
21398
+ const timelockDescription = isAddDevice ? L.timelockAddDevice : L.timelockRecovery;
21342
21399
  return /* @__PURE__ */ jsxs(
21343
21400
  "div",
21344
21401
  {
@@ -21366,18 +21423,15 @@ function Recover(props) {
21366
21423
  }
21367
21424
  )
21368
21425
  ] }),
21369
- phase === "submitting-propose" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "propose", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "submitting", children: "Submitting\u2026" }) }),
21426
+ phase === "submitting-propose" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "propose", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "submitting", children: L.submitting }) }),
21370
21427
  phase === "awaiting-timelock" && activePendingOp && /* @__PURE__ */ jsxs("section", { "data-chipi-recover-section": "awaiting", children: [
21371
21428
  /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "awaiting", children: timelockDescription }),
21372
- /* @__PURE__ */ jsxs(
21429
+ /* @__PURE__ */ jsx(
21373
21430
  "p",
21374
21431
  {
21375
21432
  "data-chipi-recover-countdown": "",
21376
21433
  "data-chipi-recover-seconds-remaining": String(secondsRemaining),
21377
- children: [
21378
- secondsRemaining,
21379
- "s remaining"
21380
- ]
21434
+ children: L.secondsRemaining(secondsRemaining)
21381
21435
  }
21382
21436
  ),
21383
21437
  /* @__PURE__ */ jsx("p", { "data-chipi-recover-op-id": "", children: String(activePendingOp.opId) }),
@@ -21388,12 +21442,12 @@ function Recover(props) {
21388
21442
  "data-chipi-recover-action": "cancel",
21389
21443
  onClick: handleCancel,
21390
21444
  disabled: submittingAction !== null,
21391
- children: "Cancel pending op"
21445
+ children: L.cancel
21392
21446
  }
21393
21447
  )
21394
21448
  ] }),
21395
21449
  (phase === "ready-to-execute" || phase === "submitting-execute") && activePendingOp && /* @__PURE__ */ jsxs("section", { "data-chipi-recover-section": "execute", children: [
21396
- /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "ready", children: "Timelock elapsed." }),
21450
+ /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "ready", children: L.timelockElapsed }),
21397
21451
  /* @__PURE__ */ jsx(
21398
21452
  "button",
21399
21453
  {
@@ -21411,12 +21465,12 @@ function Recover(props) {
21411
21465
  "data-chipi-recover-action": "cancel",
21412
21466
  onClick: handleCancel,
21413
21467
  disabled: submittingAction !== null,
21414
- children: "Cancel pending op"
21468
+ children: L.cancel
21415
21469
  }
21416
21470
  )
21417
21471
  ] }),
21418
- phase === "submitting-cancel" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "cancel", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "submitting", children: "Cancelling\u2026" }) }),
21419
- phase === "done" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "done", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "done", children: isAddDevice ? "New device added." : "Wallet recovered." }) }),
21472
+ phase === "submitting-cancel" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "cancel", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "submitting", children: L.cancelling }) }),
21473
+ phase === "done" && /* @__PURE__ */ jsx("section", { "data-chipi-recover-section": "done", children: /* @__PURE__ */ jsx("p", { "data-chipi-recover-status": "done", children: isAddDevice ? L.doneAddDevice : L.doneRecovery }) }),
21420
21474
  error && /* @__PURE__ */ jsx("p", { "data-chipi-recover-error": "", role: "alert", children: error.message })
21421
21475
  ]
21422
21476
  }
@@ -21446,6 +21500,6 @@ pako/dist/pako.esm.mjs:
21446
21500
  (*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) *)
21447
21501
  */
21448
21502
 
21449
- export { ChipiInjector, ChipiProvider, Recover, createChipiWindowObject, derivePrivacyAccount, injectChipiWallet, netPrivateBalance, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiContext, useChipiSession, useChipiWallet, useChipiWalletObject, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useGuardianRecovery, useMigrateWalletToPasskey, useMigrateWalletToShhh, usePrivateBalance, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useShhhSigner, useShield, useSignTypedData, useSyncOnChainTransfers, useThresholdSign, useTransfer, useUnshield, useUpdateWalletEncryption, useX402Payment };
21503
+ export { ChipiInjector, ChipiProvider, DEFAULT_RECOVER_LABELS, Recover, createChipiWindowObject, derivePrivacyAccount, injectChipiWallet, netPrivateBalance, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiContext, useChipiSession, useChipiWallet, useChipiWalletObject, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useGuardianRecovery, useMigrateWalletToPasskey, useMigrateWalletToShhh, usePrivateBalance, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useShhhSigner, useShield, useSignTypedData, useSyncOnChainTransfers, useThresholdSign, useTransfer, useUnshield, useUpdateWalletEncryption, useX402Payment, walletSupportsSessions };
21450
21504
  //# sourceMappingURL=index.mjs.map
21451
21505
  //# sourceMappingURL=index.mjs.map