@medialane/ui 0.257.0 → 0.259.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 (185) hide show
  1. package/dist/components/account/add-guardian-dialog.cjs +1 -1
  2. package/dist/components/account/add-guardian-dialog.cjs.map +1 -1
  3. package/dist/components/account/add-guardian-dialog.js +1 -1
  4. package/dist/components/account/add-guardian-dialog.js.map +1 -1
  5. package/dist/components/account/device-approval-dialog.cjs +2 -2
  6. package/dist/components/account/device-approval-dialog.cjs.map +1 -1
  7. package/dist/components/account/device-approval-dialog.js +2 -2
  8. package/dist/components/account/device-approval-dialog.js.map +1 -1
  9. package/dist/components/account/devices-section.cjs +1 -1
  10. package/dist/components/account/devices-section.cjs.map +1 -1
  11. package/dist/components/account/devices-section.js +1 -1
  12. package/dist/components/account/devices-section.js.map +1 -1
  13. package/dist/components/account/guardian-recovery-section.cjs +1 -1
  14. package/dist/components/account/guardian-recovery-section.cjs.map +1 -1
  15. package/dist/components/account/guardian-recovery-section.js +1 -1
  16. package/dist/components/account/guardian-recovery-section.js.map +1 -1
  17. package/dist/components/comments-section.cjs +5 -4
  18. package/dist/components/comments-section.cjs.map +1 -1
  19. package/dist/components/comments-section.js +5 -4
  20. package/dist/components/comments-section.js.map +1 -1
  21. package/dist/components/drop/create/launch-dialog.cjs +1 -1
  22. package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
  23. package/dist/components/drop/create/launch-dialog.js +1 -1
  24. package/dist/components/drop/create/launch-dialog.js.map +1 -1
  25. package/dist/components/drop/page/drop-manage.cjs +1 -1
  26. package/dist/components/drop/page/drop-manage.cjs.map +1 -1
  27. package/dist/components/drop/page/drop-manage.js +1 -1
  28. package/dist/components/drop/page/drop-manage.js.map +1 -1
  29. package/dist/components/drop/page/drop-mint-dialog.cjs +1 -1
  30. package/dist/components/drop/page/drop-mint-dialog.cjs.map +1 -1
  31. package/dist/components/drop/page/drop-mint-dialog.js +1 -1
  32. package/dist/components/drop/page/drop-mint-dialog.js.map +1 -1
  33. package/dist/components/empty-or-error.cjs +2 -2
  34. package/dist/components/empty-or-error.cjs.map +1 -1
  35. package/dist/components/empty-or-error.js +2 -2
  36. package/dist/components/empty-or-error.js.map +1 -1
  37. package/dist/components/fast-mint/fast-mint.cjs +2 -1
  38. package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
  39. package/dist/components/fast-mint/fast-mint.js +2 -1
  40. package/dist/components/fast-mint/fast-mint.js.map +1 -1
  41. package/dist/components/launchpad/coin-create.cjs +9 -7
  42. package/dist/components/launchpad/coin-create.cjs.map +1 -1
  43. package/dist/components/launchpad/coin-create.js +9 -7
  44. package/dist/components/launchpad/coin-create.js.map +1 -1
  45. package/dist/components/launchpad/collection-create-form.cjs +11 -14
  46. package/dist/components/launchpad/collection-create-form.cjs.map +1 -1
  47. package/dist/components/launchpad/collection-create-form.js +12 -15
  48. package/dist/components/launchpad/collection-create-form.js.map +1 -1
  49. package/dist/components/launchpad/collection-create-presets.cjs +8 -8
  50. package/dist/components/launchpad/collection-create-presets.cjs.map +1 -1
  51. package/dist/components/launchpad/collection-create-presets.d.cts +2 -1
  52. package/dist/components/launchpad/collection-create-presets.d.ts +2 -1
  53. package/dist/components/launchpad/collection-create-presets.js +8 -8
  54. package/dist/components/launchpad/collection-create-presets.js.map +1 -1
  55. package/dist/components/launchpad/edition-mint.cjs +9 -7
  56. package/dist/components/launchpad/edition-mint.cjs.map +1 -1
  57. package/dist/components/launchpad/edition-mint.js +9 -7
  58. package/dist/components/launchpad/edition-mint.js.map +1 -1
  59. package/dist/components/launchpad/pop-create.cjs +5 -6
  60. package/dist/components/launchpad/pop-create.cjs.map +1 -1
  61. package/dist/components/launchpad/pop-create.js +5 -6
  62. package/dist/components/launchpad/pop-create.js.map +1 -1
  63. package/dist/components/launchpad/remix-mint.cjs +9 -7
  64. package/dist/components/launchpad/remix-mint.cjs.map +1 -1
  65. package/dist/components/launchpad/remix-mint.js +9 -7
  66. package/dist/components/launchpad/remix-mint.js.map +1 -1
  67. package/dist/components/launchpad/single-edition-mint.cjs +9 -7
  68. package/dist/components/launchpad/single-edition-mint.cjs.map +1 -1
  69. package/dist/components/launchpad/single-edition-mint.js +9 -7
  70. package/dist/components/launchpad/single-edition-mint.js.map +1 -1
  71. package/dist/components/launchpad/sponsorship-create.cjs +5 -6
  72. package/dist/components/launchpad/sponsorship-create.cjs.map +1 -1
  73. package/dist/components/launchpad/sponsorship-create.js +5 -6
  74. package/dist/components/launchpad/sponsorship-create.js.map +1 -1
  75. package/dist/components/launchpad/tier-mint-form.cjs +5 -6
  76. package/dist/components/launchpad/tier-mint-form.cjs.map +1 -1
  77. package/dist/components/launchpad/tier-mint-form.js +5 -6
  78. package/dist/components/launchpad/tier-mint-form.js.map +1 -1
  79. package/dist/components/launchpad/tier-mint-presets.cjs +2 -2
  80. package/dist/components/launchpad/tier-mint-presets.cjs.map +1 -1
  81. package/dist/components/launchpad/tier-mint-presets.d.cts +2 -1
  82. package/dist/components/launchpad/tier-mint-presets.d.ts +2 -1
  83. package/dist/components/launchpad/tier-mint-presets.js +2 -2
  84. package/dist/components/launchpad/tier-mint-presets.js.map +1 -1
  85. package/dist/components/license-request-page.cjs +1 -1
  86. package/dist/components/license-request-page.cjs.map +1 -1
  87. package/dist/components/license-request-page.js +1 -1
  88. package/dist/components/license-request-page.js.map +1 -1
  89. package/dist/components/marketplace-dialog-primitives.cjs +0 -30
  90. package/dist/components/marketplace-dialog-primitives.cjs.map +1 -1
  91. package/dist/components/marketplace-dialog-primitives.d.cts +1 -12
  92. package/dist/components/marketplace-dialog-primitives.d.ts +1 -12
  93. package/dist/components/marketplace-dialog-primitives.js +1 -30
  94. package/dist/components/marketplace-dialog-primitives.js.map +1 -1
  95. package/dist/components/media-wallet/activate-card.cjs +1 -1
  96. package/dist/components/media-wallet/activate-card.cjs.map +1 -1
  97. package/dist/components/media-wallet/activate-card.js +1 -1
  98. package/dist/components/media-wallet/activate-card.js.map +1 -1
  99. package/dist/components/media-wallet/media-wallet-activity.cjs +1 -1
  100. package/dist/components/media-wallet/media-wallet-activity.cjs.map +1 -1
  101. package/dist/components/media-wallet/media-wallet-activity.js +1 -1
  102. package/dist/components/media-wallet/media-wallet-activity.js.map +1 -1
  103. package/dist/components/media-wallet/media-wallet-send.cjs +2 -6
  104. package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
  105. package/dist/components/media-wallet/media-wallet-send.js +2 -6
  106. package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
  107. package/dist/components/pop-claim-button.cjs +5 -4
  108. package/dist/components/pop-claim-button.cjs.map +1 -1
  109. package/dist/components/pop-claim-button.js +5 -4
  110. package/dist/components/pop-claim-button.js.map +1 -1
  111. package/dist/components/pop-manage-page.cjs +2 -2
  112. package/dist/components/pop-manage-page.cjs.map +1 -1
  113. package/dist/components/pop-manage-page.js +2 -2
  114. package/dist/components/pop-manage-page.js.map +1 -1
  115. package/dist/components/portfolio-sponsorships.cjs +2 -2
  116. package/dist/components/portfolio-sponsorships.cjs.map +1 -1
  117. package/dist/components/portfolio-sponsorships.js +2 -2
  118. package/dist/components/portfolio-sponsorships.js.map +1 -1
  119. package/dist/components/sponsorship-offer-page.cjs +5 -4
  120. package/dist/components/sponsorship-offer-page.cjs.map +1 -1
  121. package/dist/components/sponsorship-offer-page.js +5 -4
  122. package/dist/components/sponsorship-offer-page.js.map +1 -1
  123. package/dist/components/transaction-dialog.cjs +4 -4
  124. package/dist/components/transaction-dialog.cjs.map +1 -1
  125. package/dist/components/transaction-dialog.d.cts +3 -1
  126. package/dist/components/transaction-dialog.d.ts +3 -1
  127. package/dist/components/transaction-dialog.js +4 -4
  128. package/dist/components/transaction-dialog.js.map +1 -1
  129. package/dist/components/{creation-success.cjs → transaction-success.cjs} +14 -15
  130. package/dist/components/transaction-success.cjs.map +1 -0
  131. package/dist/components/transaction-success.d.cts +20 -0
  132. package/dist/components/transaction-success.d.ts +20 -0
  133. package/dist/components/{creation-success.js → transaction-success.js} +10 -11
  134. package/dist/components/transaction-success.js.map +1 -0
  135. package/dist/components/transfer-collection-ownership.cjs +5 -4
  136. package/dist/components/transfer-collection-ownership.cjs.map +1 -1
  137. package/dist/components/transfer-collection-ownership.js +5 -4
  138. package/dist/components/transfer-collection-ownership.js.map +1 -1
  139. package/dist/components/wallet/export-key-section.cjs +3 -3
  140. package/dist/components/wallet/export-key-section.cjs.map +1 -1
  141. package/dist/components/wallet/export-key-section.d.cts +1 -2
  142. package/dist/components/wallet/export-key-section.d.ts +1 -2
  143. package/dist/components/wallet/export-key-section.js +3 -3
  144. package/dist/components/wallet/export-key-section.js.map +1 -1
  145. package/dist/index.cjs +6 -10
  146. package/dist/index.cjs.map +1 -1
  147. package/dist/index.d.cts +4 -4
  148. package/dist/index.d.ts +4 -4
  149. package/dist/index.js +4 -8
  150. package/dist/index.js.map +1 -1
  151. package/dist/utils/describe-error.cjs +16 -11
  152. package/dist/utils/describe-error.cjs.map +1 -1
  153. package/dist/utils/describe-error.d.cts +4 -4
  154. package/dist/utils/describe-error.d.ts +4 -4
  155. package/dist/utils/describe-error.js +16 -10
  156. package/dist/utils/describe-error.js.map +1 -1
  157. package/dist/utils/media-wallet/use-erc20-balance.d.cts +1 -1
  158. package/dist/utils/media-wallet/use-erc20-balance.d.ts +1 -1
  159. package/dist/utils/success-messages.cjs +54 -0
  160. package/dist/utils/success-messages.cjs.map +1 -0
  161. package/dist/utils/success-messages.d.cts +31 -0
  162. package/dist/utils/success-messages.d.ts +31 -0
  163. package/dist/utils/success-messages.js +30 -0
  164. package/dist/utils/success-messages.js.map +1 -0
  165. package/dist/utils/use-email-code.cjs +2 -2
  166. package/dist/utils/use-email-code.cjs.map +1 -1
  167. package/dist/utils/use-email-code.js +2 -2
  168. package/dist/utils/use-email-code.js.map +1 -1
  169. package/dist/utils/use-transaction.cjs +16 -2
  170. package/dist/utils/use-transaction.cjs.map +1 -1
  171. package/dist/utils/use-transaction.d.cts +1 -0
  172. package/dist/utils/use-transaction.d.ts +1 -0
  173. package/dist/utils/use-transaction.js +17 -3
  174. package/dist/utils/use-transaction.js.map +1 -1
  175. package/package.json +3 -3
  176. package/dist/components/creation-success.cjs.map +0 -1
  177. package/dist/components/creation-success.d.cts +0 -20
  178. package/dist/components/creation-success.d.ts +0 -20
  179. package/dist/components/creation-success.js.map +0 -1
  180. package/dist/components/transaction-done.cjs +0 -46
  181. package/dist/components/transaction-done.cjs.map +0 -1
  182. package/dist/components/transaction-done.d.cts +0 -18
  183. package/dist/components/transaction-done.d.ts +0 -18
  184. package/dist/components/transaction-done.js +0 -22
  185. package/dist/components/transaction-done.js.map +0 -1
@@ -48,7 +48,7 @@ function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }) {
48
48
  setPubkey("");
49
49
  onAdded();
50
50
  } catch (e) {
51
- setError((0, import_describe_error.describeError)(e, "We couldn't add that guardian. Please try again.").message);
51
+ setError((0, import_describe_error.describeError)(e).message);
52
52
  } finally {
53
53
  setBusy(false);
54
54
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/add-guardian-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Shield, Loader2 } from \"lucide-react\";\nimport { isValidStarknetAddress, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Input } from \"../input.js\";\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { GuardianWallet } from \"./wallet-types.js\";\n\nexport interface AddGuardianDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n sealed: SealedOwner;\n onAdded: () => void;\n wallet: Pick<GuardianWallet, \"setFirstGuardian\">;\n}\n\nexport function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }: AddGuardianDialogProps) {\n const [pubkey, setPubkey] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n const trimmed = pubkey.trim();\n if (!isValidStarknetAddress(trimmed)) {\n setError(\"Enter a valid Stark-curve public key.\");\n return;\n }\n setBusy(true);\n setError(null);\n try {\n await wallet.setFirstGuardian(sealed, trimmed);\n onOpenChange(false);\n setPubkey(\"\");\n onAdded();\n } catch (e) {\n setError(describeError(e, \"We couldn't add that guardian. Please try again.\").message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Shield className=\"h-4 w-4\" /> Add a guardian\n </DialogTitle>\n <DialogDescription>\n A guardian can help you recover this wallet if you lose this device, but can\n never move your funds. Paste the public key of a wallet you control — another\n device&apos;s Media Wallet, for example. You can only set this up once from here;\n changing it later isn&apos;t supported in this app yet.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-3\">\n <Input\n value={pubkey}\n onChange={(e) => setPubkey(e.target.value)}\n placeholder=\"0x…\"\n disabled={busy}\n className=\"font-mono text-xs\"\n onKeyDown={(e) => e.key === \"Enter\" && pubkey.trim() && void handleAdd()}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={handleAdd} disabled={busy || !pubkey.trim()} className=\"w-full\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n {busy ? \"Confirm with passkey…\" : \"Add guardian\"}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgDU;AA9CV,mBAAyB;AACzB,0BAAgC;AAChC,sBAAyD;AACzD,oBAAuB;AACvB,mBAAsB;AACtB,oBAAoF;AACpF,4BAA8B;AAWvB,SAAS,kBAAkB,EAAE,MAAM,cAAc,QAAQ,SAAS,OAAO,GAA2B;AACzG,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AAEtD,QAAM,YAAY,YAAY;AAC5B,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,KAAC,wCAAuB,OAAO,GAAG;AACpC,eAAS,uCAAuC;AAChD;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,iBAAiB,QAAQ,OAAO;AAC7C,mBAAa,KAAK;AAClB,gBAAU,EAAE;AACZ,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,mBAAS,qCAAc,GAAG,kDAAkD,EAAE,OAAO;AAAA,IACvF,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,4CAAC,wBAAO,MAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,cAAa,IAAI;AAAA,EAAG,GAC3E,uDAAC,+BAAc,WAAU,eACvB;AAAA,iDAAC,8BACC;AAAA,mDAAC,6BAAY,WAAU,2BACrB;AAAA,oDAAC,8BAAO,WAAU,WAAU;AAAA,QAAE;AAAA,SAChC;AAAA,MACA,4CAAC,mCAAkB,6SAKnB;AAAA,OACF;AAAA,IACA,6CAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,aAAY;AAAA,UACZ,UAAU;AAAA,UACV,WAAU;AAAA,UACV,WAAW,CAAC,MAAM,EAAE,QAAQ,WAAW,OAAO,KAAK,KAAK,KAAK,UAAU;AAAA;AAAA,MACzE;AAAA,MACC,SAAS,4CAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,6CAAC,wBAAO,SAAS,WAAW,UAAU,QAAQ,CAAC,OAAO,KAAK,GAAG,WAAU,UACrE;AAAA,eAAO,4CAAC,+BAAQ,WAAU,mCAAkC,IAAK;AAAA,QACjE,OAAO,+BAA0B;AAAA,SACpC;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/add-guardian-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Shield, Loader2 } from \"lucide-react\";\nimport { isValidStarknetAddress, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Input } from \"../input.js\";\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { GuardianWallet } from \"./wallet-types.js\";\n\nexport interface AddGuardianDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n sealed: SealedOwner;\n onAdded: () => void;\n wallet: Pick<GuardianWallet, \"setFirstGuardian\">;\n}\n\nexport function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }: AddGuardianDialogProps) {\n const [pubkey, setPubkey] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n const trimmed = pubkey.trim();\n if (!isValidStarknetAddress(trimmed)) {\n setError(\"Enter a valid Stark-curve public key.\");\n return;\n }\n setBusy(true);\n setError(null);\n try {\n await wallet.setFirstGuardian(sealed, trimmed);\n onOpenChange(false);\n setPubkey(\"\");\n onAdded();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Shield className=\"h-4 w-4\" /> Add a guardian\n </DialogTitle>\n <DialogDescription>\n A guardian can help you recover this wallet if you lose this device, but can\n never move your funds. Paste the public key of a wallet you control — another\n device&apos;s Media Wallet, for example. You can only set this up once from here;\n changing it later isn&apos;t supported in this app yet.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-3\">\n <Input\n value={pubkey}\n onChange={(e) => setPubkey(e.target.value)}\n placeholder=\"0x…\"\n disabled={busy}\n className=\"font-mono text-xs\"\n onKeyDown={(e) => e.key === \"Enter\" && pubkey.trim() && void handleAdd()}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={handleAdd} disabled={busy || !pubkey.trim()} className=\"w-full\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n {busy ? \"Confirm with passkey…\" : \"Add guardian\"}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAgDU;AA9CV,mBAAyB;AACzB,0BAAgC;AAChC,sBAAyD;AACzD,oBAAuB;AACvB,mBAAsB;AACtB,oBAAoF;AACpF,4BAA8B;AAWvB,SAAS,kBAAkB,EAAE,MAAM,cAAc,QAAQ,SAAS,OAAO,GAA2B;AACzG,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AAEtD,QAAM,YAAY,YAAY;AAC5B,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,KAAC,wCAAuB,OAAO,GAAG;AACpC,eAAS,uCAAuC;AAChD;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,iBAAiB,QAAQ,OAAO;AAC7C,mBAAa,KAAK;AAClB,gBAAU,EAAE;AACZ,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,mBAAS,qCAAc,CAAC,EAAE,OAAO;AAAA,IACnC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,4CAAC,wBAAO,MAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,cAAa,IAAI;AAAA,EAAG,GAC3E,uDAAC,+BAAc,WAAU,eACvB;AAAA,iDAAC,8BACC;AAAA,mDAAC,6BAAY,WAAU,2BACrB;AAAA,oDAAC,8BAAO,WAAU,WAAU;AAAA,QAAE;AAAA,SAChC;AAAA,MACA,4CAAC,mCAAkB,6SAKnB;AAAA,OACF;AAAA,IACA,6CAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,aAAY;AAAA,UACZ,UAAU;AAAA,UACV,WAAU;AAAA,UACV,WAAW,CAAC,MAAM,EAAE,QAAQ,WAAW,OAAO,KAAK,KAAK,KAAK,UAAU;AAAA;AAAA,MACzE;AAAA,MACC,SAAS,4CAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,6CAAC,wBAAO,SAAS,WAAW,UAAU,QAAQ,CAAC,OAAO,KAAK,GAAG,WAAU,UACrE;AAAA,eAAO,4CAAC,+BAAQ,WAAU,mCAAkC,IAAK;AAAA,QACjE,OAAO,+BAA0B;AAAA,SACpC;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -25,7 +25,7 @@ function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }) {
25
25
  setPubkey("");
26
26
  onAdded();
27
27
  } catch (e) {
28
- setError(describeError(e, "We couldn't add that guardian. Please try again.").message);
28
+ setError(describeError(e).message);
29
29
  } finally {
30
30
  setBusy(false);
31
31
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/add-guardian-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Shield, Loader2 } from \"lucide-react\";\nimport { isValidStarknetAddress, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Input } from \"../input.js\";\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { GuardianWallet } from \"./wallet-types.js\";\n\nexport interface AddGuardianDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n sealed: SealedOwner;\n onAdded: () => void;\n wallet: Pick<GuardianWallet, \"setFirstGuardian\">;\n}\n\nexport function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }: AddGuardianDialogProps) {\n const [pubkey, setPubkey] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n const trimmed = pubkey.trim();\n if (!isValidStarknetAddress(trimmed)) {\n setError(\"Enter a valid Stark-curve public key.\");\n return;\n }\n setBusy(true);\n setError(null);\n try {\n await wallet.setFirstGuardian(sealed, trimmed);\n onOpenChange(false);\n setPubkey(\"\");\n onAdded();\n } catch (e) {\n setError(describeError(e, \"We couldn't add that guardian. Please try again.\").message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Shield className=\"h-4 w-4\" /> Add a guardian\n </DialogTitle>\n <DialogDescription>\n A guardian can help you recover this wallet if you lose this device, but can\n never move your funds. Paste the public key of a wallet you control — another\n device&apos;s Media Wallet, for example. You can only set this up once from here;\n changing it later isn&apos;t supported in this app yet.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-3\">\n <Input\n value={pubkey}\n onChange={(e) => setPubkey(e.target.value)}\n placeholder=\"0x…\"\n disabled={busy}\n className=\"font-mono text-xs\"\n onKeyDown={(e) => e.key === \"Enter\" && pubkey.trim() && void handleAdd()}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={handleAdd} disabled={busy || !pubkey.trim()} className=\"w-full\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n {busy ? \"Confirm with passkey…\" : \"Add guardian\"}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AAgDU,SACE,KADF;AA9CV,SAAS,gBAAgB;AACzB,SAAS,QAAQ,eAAe;AAChC,SAAS,8BAAgD;AACzD,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,QAAQ,eAAe,cAAc,aAAa,yBAAyB;AACpF,SAAS,qBAAqB;AAWvB,SAAS,kBAAkB,EAAE,MAAM,cAAc,QAAQ,SAAS,OAAO,GAA2B;AACzG,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AACvC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,YAAY,YAAY;AAC5B,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,CAAC,uBAAuB,OAAO,GAAG;AACpC,eAAS,uCAAuC;AAChD;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,iBAAiB,QAAQ,OAAO;AAC7C,mBAAa,KAAK;AAClB,gBAAU,EAAE;AACZ,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,eAAS,cAAc,GAAG,kDAAkD,EAAE,OAAO;AAAA,IACvF,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,oBAAC,UAAO,MAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,cAAa,IAAI;AAAA,EAAG,GAC3E,+BAAC,iBAAc,WAAU,eACvB;AAAA,yBAAC,gBACC;AAAA,2BAAC,eAAY,WAAU,2BACrB;AAAA,4BAAC,UAAO,WAAU,WAAU;AAAA,QAAE;AAAA,SAChC;AAAA,MACA,oBAAC,qBAAkB,6SAKnB;AAAA,OACF;AAAA,IACA,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,aAAY;AAAA,UACZ,UAAU;AAAA,UACV,WAAU;AAAA,UACV,WAAW,CAAC,MAAM,EAAE,QAAQ,WAAW,OAAO,KAAK,KAAK,KAAK,UAAU;AAAA;AAAA,MACzE;AAAA,MACC,SAAS,oBAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,qBAAC,UAAO,SAAS,WAAW,UAAU,QAAQ,CAAC,OAAO,KAAK,GAAG,WAAU,UACrE;AAAA,eAAO,oBAAC,WAAQ,WAAU,mCAAkC,IAAK;AAAA,QACjE,OAAO,+BAA0B;AAAA,SACpC;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/add-guardian-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Shield, Loader2 } from \"lucide-react\";\nimport { isValidStarknetAddress, type SealedOwner } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Input } from \"../input.js\";\nimport { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { GuardianWallet } from \"./wallet-types.js\";\n\nexport interface AddGuardianDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n sealed: SealedOwner;\n onAdded: () => void;\n wallet: Pick<GuardianWallet, \"setFirstGuardian\">;\n}\n\nexport function AddGuardianDialog({ open, onOpenChange, sealed, onAdded, wallet }: AddGuardianDialogProps) {\n const [pubkey, setPubkey] = useState(\"\");\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleAdd = async () => {\n const trimmed = pubkey.trim();\n if (!isValidStarknetAddress(trimmed)) {\n setError(\"Enter a valid Stark-curve public key.\");\n return;\n }\n setBusy(true);\n setError(null);\n try {\n await wallet.setFirstGuardian(sealed, trimmed);\n onOpenChange(false);\n setPubkey(\"\");\n onAdded();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog open={open} onOpenChange={(next) => { if (!busy) onOpenChange(next); }}>\n <DialogContent className=\"sm:max-w-sm\">\n <DialogHeader>\n <DialogTitle className=\"flex items-center gap-2\">\n <Shield className=\"h-4 w-4\" /> Add a guardian\n </DialogTitle>\n <DialogDescription>\n A guardian can help you recover this wallet if you lose this device, but can\n never move your funds. Paste the public key of a wallet you control — another\n device&apos;s Media Wallet, for example. You can only set this up once from here;\n changing it later isn&apos;t supported in this app yet.\n </DialogDescription>\n </DialogHeader>\n <div className=\"space-y-3\">\n <Input\n value={pubkey}\n onChange={(e) => setPubkey(e.target.value)}\n placeholder=\"0x…\"\n disabled={busy}\n className=\"font-mono text-xs\"\n onKeyDown={(e) => e.key === \"Enter\" && pubkey.trim() && void handleAdd()}\n />\n {error && <p className=\"text-sm text-destructive\">{error}</p>}\n <Button onClick={handleAdd} disabled={busy || !pubkey.trim()} className=\"w-full\">\n {busy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n {busy ? \"Confirm with passkey…\" : \"Add guardian\"}\n </Button>\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";AAgDU,SACE,KADF;AA9CV,SAAS,gBAAgB;AACzB,SAAS,QAAQ,eAAe;AAChC,SAAS,8BAAgD;AACzD,SAAS,cAAc;AACvB,SAAS,aAAa;AACtB,SAAS,QAAQ,eAAe,cAAc,aAAa,yBAAyB;AACpF,SAAS,qBAAqB;AAWvB,SAAS,kBAAkB,EAAE,MAAM,cAAc,QAAQ,SAAS,OAAO,GAA2B;AACzG,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,EAAE;AACvC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AAEtD,QAAM,YAAY,YAAY;AAC5B,UAAM,UAAU,OAAO,KAAK;AAC5B,QAAI,CAAC,uBAAuB,OAAO,GAAG;AACpC,eAAS,uCAAuC;AAChD;AAAA,IACF;AACA,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,iBAAiB,QAAQ,OAAO;AAC7C,mBAAa,KAAK;AAClB,gBAAU,EAAE;AACZ,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,eAAS,cAAc,CAAC,EAAE,OAAO;AAAA,IACnC,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE,oBAAC,UAAO,MAAY,cAAc,CAAC,SAAS;AAAE,QAAI,CAAC,KAAM,cAAa,IAAI;AAAA,EAAG,GAC3E,+BAAC,iBAAc,WAAU,eACvB;AAAA,yBAAC,gBACC;AAAA,2BAAC,eAAY,WAAU,2BACrB;AAAA,4BAAC,UAAO,WAAU,WAAU;AAAA,QAAE;AAAA,SAChC;AAAA,MACA,oBAAC,qBAAkB,6SAKnB;AAAA,OACF;AAAA,IACA,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA,UACzC,aAAY;AAAA,UACZ,UAAU;AAAA,UACV,WAAU;AAAA,UACV,WAAW,CAAC,MAAM,EAAE,QAAQ,WAAW,OAAO,KAAK,KAAK,KAAK,UAAU;AAAA;AAAA,MACzE;AAAA,MACC,SAAS,oBAAC,OAAE,WAAU,4BAA4B,iBAAM;AAAA,MACzD,qBAAC,UAAO,SAAS,WAAW,UAAU,QAAQ,CAAC,OAAO,KAAK,GAAG,WAAU,UACrE;AAAA,eAAO,oBAAC,WAAQ,WAAU,mCAAkC,IAAK;AAAA,QACjE,OAAO,+BAA0B;AAAA,SACpC;AAAA,OACF;AAAA,KACF,GACF;AAEJ;","names":[]}
@@ -46,7 +46,7 @@ function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSeal
46
46
  try {
47
47
  setPending((0, import_starknet.parsePairingPayload)(raw.trim()));
48
48
  } catch (e) {
49
- setError((0, import_describe_error.describeError)(e, "That device code isn't valid. Check it and try again.").message);
49
+ setError((0, import_describe_error.describeError)(e).message);
50
50
  }
51
51
  };
52
52
  const approve = async () => {
@@ -60,7 +60,7 @@ function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSeal
60
60
  onOpenChange(false);
61
61
  onApproved();
62
62
  } catch (e) {
63
- setError((0, import_describe_error.describeError)(e, "We couldn't approve that device. Please try again.").message);
63
+ setError((0, import_describe_error.describeError)(e).message);
64
64
  } finally {
65
65
  setBusy(false);
66
66
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/device-approval-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Loader2, Smartphone, TriangleAlert } from \"lucide-react\";\nimport { parsePairingPayload, type PairingPayload } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nexport interface DeviceApprovalDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onApproved: () => void;\n wallet: Pick<DeviceWallet, \"addDevice\">;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSealed }: DeviceApprovalDialogProps) {\n const [raw, setRaw] = useState(\"\");\n const [pending, setPending] = useState<PairingPayload | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const reset = () => {\n setRaw(\"\");\n setPending(null);\n setError(null);\n };\n\n const review = () => {\n setError(null);\n try {\n setPending(parsePairingPayload(raw.trim()));\n } catch (e) {\n setError(describeError(e, \"That device code isn't valid. Check it and try again.\").message);\n }\n };\n\n const approve = async () => {\n const sealed = loadSealed();\n if (!sealed || !pending) return;\n setBusy(true);\n setError(null);\n try {\n await wallet.addDevice(sealed, pending.publicKey);\n reset();\n onOpenChange(false);\n onApproved();\n } catch (e) {\n setError(describeError(e, \"We couldn't approve that device. Please try again.\").message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) reset();\n onOpenChange(next);\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add a device</DialogTitle>\n <DialogDescription>\n On the new device, sign in and choose &ldquo;Add this device&rdquo;. Paste the code it\n shows you here.\n </DialogDescription>\n </DialogHeader>\n\n {pending ? (\n <div className=\"space-y-4\">\n <Alert>\n <TriangleAlert className=\"h-4 w-4\" />\n <AlertDescription>\n This gives the device full control of your account and everything in it. Only\n continue if you are holding it yourself.\n </AlertDescription>\n </Alert>\n\n <div className=\"rounded-xl bg-muted/50 p-4 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{pending.label || \"Unnamed device\"}</span>\n </div>\n <p className=\"break-all font-mono text-xs text-muted-foreground\">\n {pending.publicKey}\n </p>\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" className=\"flex-1\" onClick={reset} disabled={busy}>\n Back\n </Button>\n <Button className=\"flex-1\" onClick={approve} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Approve device\"}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <Textarea\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n placeholder=\"Paste the code from your other device\"\n rows={4}\n className=\"font-mono text-xs\"\n />\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n <Button className=\"w-full\" onClick={review} disabled={!raw.trim()}>\n Review device\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmEQ;AAjER,mBAAyB;AACzB,0BAAmD;AACnD,sBAAyD;AACzD,oBAAuB;AACvB,sBAAyB;AACzB,mBAAwC;AACxC,oBAAoF;AACpF,4BAA8B;AAWvB,SAAS,qBAAqB,EAAE,MAAM,cAAc,YAAY,QAAQ,WAAW,GAA8B;AACtH,QAAM,CAAC,KAAK,MAAM,QAAI,uBAAS,EAAE;AACjC,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAgC,IAAI;AAClE,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAwB,IAAI;AAEtD,QAAM,QAAQ,MAAM;AAClB,WAAO,EAAE;AACT,eAAW,IAAI;AACf,aAAS,IAAI;AAAA,EACf;AAEA,QAAM,SAAS,MAAM;AACnB,aAAS,IAAI;AACb,QAAI;AACF,qBAAW,qCAAoB,IAAI,KAAK,CAAC,CAAC;AAAA,IAC5C,SAAS,GAAG;AACV,mBAAS,qCAAc,GAAG,uDAAuD,EAAE,OAAO;AAAA,IAC5F;AAAA,EACF;AAEA,QAAM,UAAU,YAAY;AAC1B,UAAM,SAAS,WAAW;AAC1B,QAAI,CAAC,UAAU,CAAC,QAAS;AACzB,YAAQ,IAAI;AACZ,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,UAAU,QAAQ,QAAQ,SAAS;AAChD,YAAM;AACN,mBAAa,KAAK;AAClB,iBAAW;AAAA,IACb,SAAS,GAAG;AACV,mBAAS,qCAAc,GAAG,oDAAoD,EAAE,OAAO;AAAA,IACzF,UAAE;AACA,cAAQ,KAAK;AAAA,IACf;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,cAAc,CAAC,SAAS;AACtB,YAAI,CAAC,KAAM,OAAM;AACjB,qBAAa,IAAI;AAAA,MACnB;AAAA,MAEA,uDAAC,+BACC;AAAA,qDAAC,8BACC;AAAA,sDAAC,6BAAY,0BAAY;AAAA,UACzB,4CAAC,mCAAkB,kHAGnB;AAAA,WACF;AAAA,QAEC,UACC,6CAAC,SAAI,WAAU,aACb;AAAA,uDAAC,sBACC;AAAA,wDAAC,qCAAc,WAAU,WAAU;AAAA,YACnC,4CAAC,iCAAiB,oIAGlB;AAAA,aACF;AAAA,UAEA,6CAAC,SAAI,WAAU,wCACb;AAAA,yDAAC,SAAI,WAAU,2BACb;AAAA,0DAAC,kCAAW,WAAU,iCAAgC;AAAA,cACtD,4CAAC,UAAK,WAAU,eAAe,kBAAQ,SAAS,kBAAiB;AAAA,eACnE;AAAA,YACA,4CAAC,OAAE,WAAU,qDACV,kBAAQ,WACX;AAAA,aACF;AAAA,UAEC,QAAQ,4CAAC,OAAE,WAAU,4BAA4B,iBAAM,IAAO;AAAA,UAE/D,6CAAC,SAAI,WAAU,cACb;AAAA,wDAAC,wBAAO,SAAQ,WAAU,WAAU,UAAS,SAAS,OAAO,UAAU,MAAM,kBAE7E;AAAA,YACA,4CAAC,wBAAO,WAAU,UAAS,SAAS,SAAS,UAAU,MACpD,iBAAO,4CAAC,+BAAQ,WAAU,wBAAuB,IAAK,kBACzD;AAAA,aACF;AAAA,WACF,IAEA,6CAAC,SAAI,WAAU,aACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,OAAO,EAAE,OAAO,KAAK;AAAA,cACtC,aAAY;AAAA,cACZ,MAAM;AAAA,cACN,WAAU;AAAA;AAAA,UACZ;AAAA,UACC,QAAQ,4CAAC,OAAE,WAAU,4BAA4B,iBAAM,IAAO;AAAA,UAC/D,4CAAC,wBAAO,WAAU,UAAS,SAAS,QAAQ,UAAU,CAAC,IAAI,KAAK,GAAG,2BAEnE;AAAA,WACF;AAAA,SAEJ;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/device-approval-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Loader2, Smartphone, TriangleAlert } from \"lucide-react\";\nimport { parsePairingPayload, type PairingPayload } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nexport interface DeviceApprovalDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onApproved: () => void;\n wallet: Pick<DeviceWallet, \"addDevice\">;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSealed }: DeviceApprovalDialogProps) {\n const [raw, setRaw] = useState(\"\");\n const [pending, setPending] = useState<PairingPayload | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const reset = () => {\n setRaw(\"\");\n setPending(null);\n setError(null);\n };\n\n const review = () => {\n setError(null);\n try {\n setPending(parsePairingPayload(raw.trim()));\n } catch (e) {\n setError(describeError(e).message);\n }\n };\n\n const approve = async () => {\n const sealed = loadSealed();\n if (!sealed || !pending) return;\n setBusy(true);\n setError(null);\n try {\n await wallet.addDevice(sealed, pending.publicKey);\n reset();\n onOpenChange(false);\n onApproved();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) reset();\n onOpenChange(next);\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add a device</DialogTitle>\n <DialogDescription>\n On the new device, sign in and choose &ldquo;Add this device&rdquo;. Paste the code it\n shows you here.\n </DialogDescription>\n </DialogHeader>\n\n {pending ? (\n <div className=\"space-y-4\">\n <Alert>\n <TriangleAlert className=\"h-4 w-4\" />\n <AlertDescription>\n This gives the device full control of your account and everything in it. Only\n continue if you are holding it yourself.\n </AlertDescription>\n </Alert>\n\n <div className=\"rounded-xl bg-muted/50 p-4 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{pending.label || \"Unnamed device\"}</span>\n </div>\n <p className=\"break-all font-mono text-xs text-muted-foreground\">\n {pending.publicKey}\n </p>\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" className=\"flex-1\" onClick={reset} disabled={busy}>\n Back\n </Button>\n <Button className=\"flex-1\" onClick={approve} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Approve device\"}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <Textarea\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n placeholder=\"Paste the code from your other device\"\n rows={4}\n className=\"font-mono text-xs\"\n />\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n <Button className=\"w-full\" onClick={review} disabled={!raw.trim()}>\n Review device\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -23,7 +23,7 @@ function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSeal
23
23
  try {
24
24
  setPending(parsePairingPayload(raw.trim()));
25
25
  } catch (e) {
26
- setError(describeError(e, "That device code isn't valid. Check it and try again.").message);
26
+ setError(describeError(e).message);
27
27
  }
28
28
  };
29
29
  const approve = async () => {
@@ -37,7 +37,7 @@ function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSeal
37
37
  onOpenChange(false);
38
38
  onApproved();
39
39
  } catch (e) {
40
- setError(describeError(e, "We couldn't approve that device. Please try again.").message);
40
+ setError(describeError(e).message);
41
41
  } finally {
42
42
  setBusy(false);
43
43
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/device-approval-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Loader2, Smartphone, TriangleAlert } from \"lucide-react\";\nimport { parsePairingPayload, type PairingPayload } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nexport interface DeviceApprovalDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onApproved: () => void;\n wallet: Pick<DeviceWallet, \"addDevice\">;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSealed }: DeviceApprovalDialogProps) {\n const [raw, setRaw] = useState(\"\");\n const [pending, setPending] = useState<PairingPayload | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const reset = () => {\n setRaw(\"\");\n setPending(null);\n setError(null);\n };\n\n const review = () => {\n setError(null);\n try {\n setPending(parsePairingPayload(raw.trim()));\n } catch (e) {\n setError(describeError(e, \"That device code isn't valid. Check it and try again.\").message);\n }\n };\n\n const approve = async () => {\n const sealed = loadSealed();\n if (!sealed || !pending) return;\n setBusy(true);\n setError(null);\n try {\n await wallet.addDevice(sealed, pending.publicKey);\n reset();\n onOpenChange(false);\n onApproved();\n } catch (e) {\n setError(describeError(e, \"We couldn't approve that device. Please try again.\").message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) reset();\n onOpenChange(next);\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add a device</DialogTitle>\n <DialogDescription>\n On the new device, sign in and choose &ldquo;Add this device&rdquo;. Paste the code it\n shows you here.\n </DialogDescription>\n </DialogHeader>\n\n {pending ? (\n <div className=\"space-y-4\">\n <Alert>\n <TriangleAlert className=\"h-4 w-4\" />\n <AlertDescription>\n This gives the device full control of your account and everything in it. Only\n continue if you are holding it yourself.\n </AlertDescription>\n </Alert>\n\n <div className=\"rounded-xl bg-muted/50 p-4 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{pending.label || \"Unnamed device\"}</span>\n </div>\n <p className=\"break-all font-mono text-xs text-muted-foreground\">\n {pending.publicKey}\n </p>\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" className=\"flex-1\" onClick={reset} disabled={busy}>\n Back\n </Button>\n <Button className=\"flex-1\" onClick={approve} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Approve device\"}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <Textarea\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n placeholder=\"Paste the code from your other device\"\n rows={4}\n className=\"font-mono text-xs\"\n />\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n <Button className=\"w-full\" onClick={review} disabled={!raw.trim()}>\n Review device\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/device-approval-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Loader2, Smartphone, TriangleAlert } from \"lucide-react\";\nimport { parsePairingPayload, type PairingPayload } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Textarea } from \"../textarea.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from \"../dialog.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nexport interface DeviceApprovalDialogProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onApproved: () => void;\n wallet: Pick<DeviceWallet, \"addDevice\">;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DeviceApprovalDialog({ open, onOpenChange, onApproved, wallet, loadSealed }: DeviceApprovalDialogProps) {\n const [raw, setRaw] = useState(\"\");\n const [pending, setPending] = useState<PairingPayload | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const reset = () => {\n setRaw(\"\");\n setPending(null);\n setError(null);\n };\n\n const review = () => {\n setError(null);\n try {\n setPending(parsePairingPayload(raw.trim()));\n } catch (e) {\n setError(describeError(e).message);\n }\n };\n\n const approve = async () => {\n const sealed = loadSealed();\n if (!sealed || !pending) return;\n setBusy(true);\n setError(null);\n try {\n await wallet.addDevice(sealed, pending.publicKey);\n reset();\n onOpenChange(false);\n onApproved();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusy(false);\n }\n };\n\n return (\n <Dialog\n open={open}\n onOpenChange={(next) => {\n if (!next) reset();\n onOpenChange(next);\n }}\n >\n <DialogContent>\n <DialogHeader>\n <DialogTitle>Add a device</DialogTitle>\n <DialogDescription>\n On the new device, sign in and choose &ldquo;Add this device&rdquo;. Paste the code it\n shows you here.\n </DialogDescription>\n </DialogHeader>\n\n {pending ? (\n <div className=\"space-y-4\">\n <Alert>\n <TriangleAlert className=\"h-4 w-4\" />\n <AlertDescription>\n This gives the device full control of your account and everything in it. Only\n continue if you are holding it yourself.\n </AlertDescription>\n </Alert>\n\n <div className=\"rounded-xl bg-muted/50 p-4 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <Smartphone className=\"h-4 w-4 text-muted-foreground\" />\n <span className=\"font-medium\">{pending.label || \"Unnamed device\"}</span>\n </div>\n <p className=\"break-all font-mono text-xs text-muted-foreground\">\n {pending.publicKey}\n </p>\n </div>\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" className=\"flex-1\" onClick={reset} disabled={busy}>\n Back\n </Button>\n <Button className=\"flex-1\" onClick={approve} disabled={busy}>\n {busy ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Approve device\"}\n </Button>\n </div>\n </div>\n ) : (\n <div className=\"space-y-4\">\n <Textarea\n value={raw}\n onChange={(e) => setRaw(e.target.value)}\n placeholder=\"Paste the code from your other device\"\n rows={4}\n className=\"font-mono text-xs\"\n />\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n <Button className=\"w-full\" onClick={review} disabled={!raw.trim()}>\n Review device\n </Button>\n </div>\n )}\n </DialogContent>\n </Dialog>\n );\n}\n"],"mappings":"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","names":[]}
@@ -57,7 +57,7 @@ function DevicesSection({ walletAddress, wallet, loadSealed }) {
57
57
  await wallet.removeDevice(sealed, device.guid);
58
58
  refresh();
59
59
  } catch (e) {
60
- setError((0, import_describe_error.describeError)(e, "We couldn't remove that device. Please try again.").message);
60
+ setError((0, import_describe_error.describeError)(e).message);
61
61
  } finally {
62
62
  setBusyGuid(null);
63
63
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/devices-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Loader2, Monitor, Plus } from \"lucide-react\";\nimport { canRemoveDevice, describeDevices, type DeviceEntry } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { DeviceApprovalDialog } from \"./device-approval-dialog.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (v: string) => `${v.slice(0, 10)}…${v.slice(-6)}`;\n\nexport interface DevicesSectionProps {\n walletAddress: string;\n wallet: DeviceWallet;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DevicesSection({ walletAddress, wallet, loadSealed }: DevicesSectionProps) {\n const [devices, setDevices] = useState<DeviceEntry[] | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [busyGuid, setBusyGuid] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n const sealed = loadSealed();\n if (!sealed) return;\n wallet\n .getOwners(walletAddress)\n .then((owners) => setDevices(describeDevices(owners, sealed.ownerPubKey)))\n .catch(() => setDevices([]));\n }, [walletAddress, wallet, loadSealed]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n const handleRemove = async (device: DeviceEntry) => {\n const sealed = loadSealed();\n if (!sealed || !devices) return;\n\n const confirmed = window.confirm(\n \"Remove this device? It will no longer be able to sign for your account. Adding it back needs a device you still have.\",\n );\n if (!confirmed) return;\n\n setBusyGuid(device.guid);\n setError(null);\n try {\n await wallet.removeDevice(sealed, device.guid);\n refresh();\n } catch (e) {\n setError(describeError(e, \"We couldn't remove that device. Please try again.\").message);\n } finally {\n setBusyGuid(null);\n }\n };\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Your devices</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n Each device signs for itself. Add one to use this account somewhere else.\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setAddOpen(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add\n </Button>\n </div>\n\n {devices === null ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-muted-foreground\" />\n ) : devices.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No devices found for this account.</p>\n ) : (\n <ul className=\"space-y-2\">\n {devices.map((device) => (\n <li\n key={device.guid}\n className=\"flex items-center justify-between gap-3 rounded-xl bg-muted/40 px-4 py-3\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Monitor className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"font-mono text-xs text-muted-foreground truncate\">\n {short(device.guid)}\n </span>\n {device.isThisDevice ? <Badge variant=\"secondary\">This device</Badge> : null}\n </div>\n {device.isThisDevice ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={!canRemoveDevice(devices, device.guid) || busyGuid !== null}\n onClick={() => handleRemove(device)}\n >\n {busyGuid === device.guid ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Remove\"}\n </Button>\n )}\n </li>\n ))}\n </ul>\n )}\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <DeviceApprovalDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n onApproved={refresh}\n wallet={wallet}\n loadSealed={loadSealed}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/devices-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Loader2, Monitor, Plus } from \"lucide-react\";\nimport { canRemoveDevice, describeDevices, type DeviceEntry } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { DeviceApprovalDialog } from \"./device-approval-dialog.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (v: string) => `${v.slice(0, 10)}…${v.slice(-6)}`;\n\nexport interface DevicesSectionProps {\n walletAddress: string;\n wallet: DeviceWallet;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DevicesSection({ walletAddress, wallet, loadSealed }: DevicesSectionProps) {\n const [devices, setDevices] = useState<DeviceEntry[] | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [busyGuid, setBusyGuid] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n const sealed = loadSealed();\n if (!sealed) return;\n wallet\n .getOwners(walletAddress)\n .then((owners) => setDevices(describeDevices(owners, sealed.ownerPubKey)))\n .catch(() => setDevices([]));\n }, [walletAddress, wallet, loadSealed]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n const handleRemove = async (device: DeviceEntry) => {\n const sealed = loadSealed();\n if (!sealed || !devices) return;\n\n const confirmed = window.confirm(\n \"Remove this device? It will no longer be able to sign for your account. Adding it back needs a device you still have.\",\n );\n if (!confirmed) return;\n\n setBusyGuid(device.guid);\n setError(null);\n try {\n await wallet.removeDevice(sealed, device.guid);\n refresh();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusyGuid(null);\n }\n };\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Your devices</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n Each device signs for itself. Add one to use this account somewhere else.\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setAddOpen(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add\n </Button>\n </div>\n\n {devices === null ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-muted-foreground\" />\n ) : devices.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No devices found for this account.</p>\n ) : (\n <ul className=\"space-y-2\">\n {devices.map((device) => (\n <li\n key={device.guid}\n className=\"flex items-center justify-between gap-3 rounded-xl bg-muted/40 px-4 py-3\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Monitor className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"font-mono text-xs text-muted-foreground truncate\">\n {short(device.guid)}\n </span>\n {device.isThisDevice ? <Badge variant=\"secondary\">This device</Badge> : null}\n </div>\n {device.isThisDevice ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={!canRemoveDevice(devices, device.guid) || busyGuid !== null}\n onClick={() => handleRemove(device)}\n >\n {busyGuid === device.guid ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Remove\"}\n </Button>\n )}\n </li>\n ))}\n </ul>\n )}\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <DeviceApprovalDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n onApproved={refresh}\n wallet={wallet}\n loadSealed={loadSealed}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -34,7 +34,7 @@ function DevicesSection({ walletAddress, wallet, loadSealed }) {
34
34
  await wallet.removeDevice(sealed, device.guid);
35
35
  refresh();
36
36
  } catch (e) {
37
- setError(describeError(e, "We couldn't remove that device. Please try again.").message);
37
+ setError(describeError(e).message);
38
38
  } finally {
39
39
  setBusyGuid(null);
40
40
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/devices-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Loader2, Monitor, Plus } from \"lucide-react\";\nimport { canRemoveDevice, describeDevices, type DeviceEntry } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { DeviceApprovalDialog } from \"./device-approval-dialog.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (v: string) => `${v.slice(0, 10)}…${v.slice(-6)}`;\n\nexport interface DevicesSectionProps {\n walletAddress: string;\n wallet: DeviceWallet;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DevicesSection({ walletAddress, wallet, loadSealed }: DevicesSectionProps) {\n const [devices, setDevices] = useState<DeviceEntry[] | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [busyGuid, setBusyGuid] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n const sealed = loadSealed();\n if (!sealed) return;\n wallet\n .getOwners(walletAddress)\n .then((owners) => setDevices(describeDevices(owners, sealed.ownerPubKey)))\n .catch(() => setDevices([]));\n }, [walletAddress, wallet, loadSealed]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n const handleRemove = async (device: DeviceEntry) => {\n const sealed = loadSealed();\n if (!sealed || !devices) return;\n\n const confirmed = window.confirm(\n \"Remove this device? It will no longer be able to sign for your account. Adding it back needs a device you still have.\",\n );\n if (!confirmed) return;\n\n setBusyGuid(device.guid);\n setError(null);\n try {\n await wallet.removeDevice(sealed, device.guid);\n refresh();\n } catch (e) {\n setError(describeError(e, \"We couldn't remove that device. Please try again.\").message);\n } finally {\n setBusyGuid(null);\n }\n };\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Your devices</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n Each device signs for itself. Add one to use this account somewhere else.\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setAddOpen(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add\n </Button>\n </div>\n\n {devices === null ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-muted-foreground\" />\n ) : devices.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No devices found for this account.</p>\n ) : (\n <ul className=\"space-y-2\">\n {devices.map((device) => (\n <li\n key={device.guid}\n className=\"flex items-center justify-between gap-3 rounded-xl bg-muted/40 px-4 py-3\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Monitor className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"font-mono text-xs text-muted-foreground truncate\">\n {short(device.guid)}\n </span>\n {device.isThisDevice ? <Badge variant=\"secondary\">This device</Badge> : null}\n </div>\n {device.isThisDevice ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={!canRemoveDevice(devices, device.guid) || busyGuid !== null}\n onClick={() => handleRemove(device)}\n >\n {busyGuid === device.guid ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Remove\"}\n </Button>\n )}\n </li>\n ))}\n </ul>\n )}\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <DeviceApprovalDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n onApproved={refresh}\n wallet={wallet}\n loadSealed={loadSealed}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/account/devices-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Loader2, Monitor, Plus } from \"lucide-react\";\nimport { canRemoveDevice, describeDevices, type DeviceEntry } from \"@medialane/sdk/starknet\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { DeviceApprovalDialog } from \"./device-approval-dialog.js\";\nimport type { DeviceWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (v: string) => `${v.slice(0, 10)}…${v.slice(-6)}`;\n\nexport interface DevicesSectionProps {\n walletAddress: string;\n wallet: DeviceWallet;\n loadSealed: LoadSealedOwner;\n}\n\nexport function DevicesSection({ walletAddress, wallet, loadSealed }: DevicesSectionProps) {\n const [devices, setDevices] = useState<DeviceEntry[] | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [busyGuid, setBusyGuid] = useState<string | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n const sealed = loadSealed();\n if (!sealed) return;\n wallet\n .getOwners(walletAddress)\n .then((owners) => setDevices(describeDevices(owners, sealed.ownerPubKey)))\n .catch(() => setDevices([]));\n }, [walletAddress, wallet, loadSealed]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n const handleRemove = async (device: DeviceEntry) => {\n const sealed = loadSealed();\n if (!sealed || !devices) return;\n\n const confirmed = window.confirm(\n \"Remove this device? It will no longer be able to sign for your account. Adding it back needs a device you still have.\",\n );\n if (!confirmed) return;\n\n setBusyGuid(device.guid);\n setError(null);\n try {\n await wallet.removeDevice(sealed, device.guid);\n refresh();\n } catch (e) {\n setError(describeError(e).message);\n } finally {\n setBusyGuid(null);\n }\n };\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Your devices</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n Each device signs for itself. Add one to use this account somewhere else.\n </p>\n </div>\n <Button size=\"sm\" variant=\"outline\" onClick={() => setAddOpen(true)}>\n <Plus className=\"h-4 w-4 mr-1\" />\n Add\n </Button>\n </div>\n\n {devices === null ? (\n <Loader2 className=\"h-4 w-4 animate-spin text-muted-foreground\" />\n ) : devices.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">No devices found for this account.</p>\n ) : (\n <ul className=\"space-y-2\">\n {devices.map((device) => (\n <li\n key={device.guid}\n className=\"flex items-center justify-between gap-3 rounded-xl bg-muted/40 px-4 py-3\"\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <Monitor className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span className=\"font-mono text-xs text-muted-foreground truncate\">\n {short(device.guid)}\n </span>\n {device.isThisDevice ? <Badge variant=\"secondary\">This device</Badge> : null}\n </div>\n {device.isThisDevice ? null : (\n <Button\n size=\"sm\"\n variant=\"ghost\"\n disabled={!canRemoveDevice(devices, device.guid) || busyGuid !== null}\n onClick={() => handleRemove(device)}\n >\n {busyGuid === device.guid ? <Loader2 className=\"h-4 w-4 animate-spin\" /> : \"Remove\"}\n </Button>\n )}\n </li>\n ))}\n </ul>\n )}\n\n {error ? <p className=\"text-sm text-destructive\">{error}</p> : null}\n\n <DeviceApprovalDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n onApproved={refresh}\n wallet={wallet}\n loadSealed={loadSealed}\n />\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -71,7 +71,7 @@ function GuardianRecoverySection({
71
71
  await wallet.cancelEscape(sealed2);
72
72
  refresh();
73
73
  } catch (e) {
74
- setCancelError((0, import_describe_error.describeError)(e, "We couldn't cancel recovery. Please try again.").message);
74
+ setCancelError((0, import_describe_error.describeError)(e).message);
75
75
  } finally {
76
76
  setCancelBusy(false);
77
77
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/guardian-recovery-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Shield, ShieldAlert, ChevronRight, Loader2 } from \"lucide-react\";\nimport {\n describeGuardianStatus,\n describeRecoveryAction,\n type EscapeInfo,\n type GuardianInfo,\n} from \"@medialane/sdk/starknet\";\nimport Link from \"../link.js\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { AddGuardianDialog } from \"./add-guardian-dialog.js\";\nimport type { GuardianWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (a: string) => `${a.slice(0, 6)}…${a.slice(-4)}`;\n\nexport interface GuardianRecoverySectionProps {\n walletAddress: string;\n wallet: GuardianWallet;\n loadSealed: LoadSealedOwner;\n guardianRecoveryAvailable: boolean;\n recoverHref?: string;\n}\n\nexport function GuardianRecoverySection({\n walletAddress,\n wallet,\n loadSealed,\n guardianRecoveryAvailable,\n recoverHref = \"/recover\",\n}: GuardianRecoverySectionProps) {\n const [guardians, setGuardians] = useState<GuardianInfo[] | null>(null);\n const [escape, setEscape] = useState<EscapeInfo | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [cancelBusy, setCancelBusy] = useState(false);\n const [cancelError, setCancelError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n wallet.getGuardians(walletAddress).then(setGuardians).catch(() => setGuardians([]));\n wallet.getEscape(walletAddress).then(setEscape).catch(() => setEscape(null));\n }, [walletAddress, wallet]);\n\n useEffect(() => { refresh(); }, [refresh]);\n\n const handleCancel = async () => {\n const sealed = loadSealed();\n if (!sealed) return;\n setCancelBusy(true);\n setCancelError(null);\n try {\n await wallet.cancelEscape(sealed);\n refresh();\n } catch (e) {\n setCancelError(describeError(e, \"We couldn't cancel recovery. Please try again.\").message);\n } finally {\n setCancelBusy(false);\n }\n };\n\n const status = guardians ? describeGuardianStatus(guardians) : null;\n const recoveryAction = escape ? describeRecoveryAction(escape) : \"none\";\n const inProgress = escape?.escapeType === \"Owner\" && recoveryAction !== \"none\" ? escape : null;\n\n const sealed = loadSealed();\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"h-10 w-10 shrink-0 rounded-full bg-emerald-500/10 flex items-center justify-center\">\n <Shield className=\"h-5 w-5 text-emerald-600 dark:text-emerald-400\" />\n </div>\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Security &amp; Recovery</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n A guardian can help you get back into this wallet if you ever lose this device.\n </p>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {inProgress && (\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription>\n A guardian has started replacing this wallet&apos;s owner key.{\" \"}\n {inProgress.status === \"Ready\"\n ? \"It can complete at any time.\"\n : `It can complete on ${new Date(inProgress.readyAt * 1000).toLocaleString()}.`}{\" \"}\n If this wasn&apos;t you, cancel it now.\n {cancelError && <p className=\"mt-1 text-destructive\">{cancelError}</p>}\n <Button\n onClick={handleCancel}\n disabled={cancelBusy}\n variant=\"destructive\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n >\n {cancelBusy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n Cancel recovery\n </Button>\n </AlertDescription>\n </Alert>\n )}\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 flex-wrap\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Guardian recovery</p>\n {status === null ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">Checking…</p>\n ) : status.kind === \"none\" ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {guardianRecoveryAvailable ? \"Not set up — add one from another device you trust.\" : \"Not available yet.\"}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Active: {status.guardian.type} guardian {short(status.guardian.storedValue)}\n </p>\n )}\n </div>\n {status?.kind === \"none\" && sealed && (\n <Button onClick={() => setAddOpen(true)} variant=\"outline\" size=\"sm\" disabled={!guardianRecoveryAvailable}>\n Add guardian\n </Button>\n )}\n {status?.kind === \"active\" && (\n <Badge variant=\"outline\" className=\"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 text-2xs\">\n Configured\n </Badge>\n )}\n </div>\n\n <Link\n href={recoverHref}\n className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 transition-colors hover:bg-foreground/[0.03]\"\n >\n <div>\n <p className=\"text-sm font-medium text-foreground\">Recover a wallet</p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Lost this device, or acting as someone&apos;s guardian?\n </p>\n </div>\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n </Link>\n </div>\n\n {sealed && guardianRecoveryAvailable && (\n <AddGuardianDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n sealed={sealed}\n onAdded={refresh}\n wallet={wallet}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["sealed","Link"]}
1
+ {"version":3,"sources":["../../../src/components/account/guardian-recovery-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Shield, ShieldAlert, ChevronRight, Loader2 } from \"lucide-react\";\nimport {\n describeGuardianStatus,\n describeRecoveryAction,\n type EscapeInfo,\n type GuardianInfo,\n} from \"@medialane/sdk/starknet\";\nimport Link from \"../link.js\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { AddGuardianDialog } from \"./add-guardian-dialog.js\";\nimport type { GuardianWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (a: string) => `${a.slice(0, 6)}…${a.slice(-4)}`;\n\nexport interface GuardianRecoverySectionProps {\n walletAddress: string;\n wallet: GuardianWallet;\n loadSealed: LoadSealedOwner;\n guardianRecoveryAvailable: boolean;\n recoverHref?: string;\n}\n\nexport function GuardianRecoverySection({\n walletAddress,\n wallet,\n loadSealed,\n guardianRecoveryAvailable,\n recoverHref = \"/recover\",\n}: GuardianRecoverySectionProps) {\n const [guardians, setGuardians] = useState<GuardianInfo[] | null>(null);\n const [escape, setEscape] = useState<EscapeInfo | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [cancelBusy, setCancelBusy] = useState(false);\n const [cancelError, setCancelError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n wallet.getGuardians(walletAddress).then(setGuardians).catch(() => setGuardians([]));\n wallet.getEscape(walletAddress).then(setEscape).catch(() => setEscape(null));\n }, [walletAddress, wallet]);\n\n useEffect(() => { refresh(); }, [refresh]);\n\n const handleCancel = async () => {\n const sealed = loadSealed();\n if (!sealed) return;\n setCancelBusy(true);\n setCancelError(null);\n try {\n await wallet.cancelEscape(sealed);\n refresh();\n } catch (e) {\n setCancelError(describeError(e).message);\n } finally {\n setCancelBusy(false);\n }\n };\n\n const status = guardians ? describeGuardianStatus(guardians) : null;\n const recoveryAction = escape ? describeRecoveryAction(escape) : \"none\";\n const inProgress = escape?.escapeType === \"Owner\" && recoveryAction !== \"none\" ? escape : null;\n\n const sealed = loadSealed();\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"h-10 w-10 shrink-0 rounded-full bg-emerald-500/10 flex items-center justify-center\">\n <Shield className=\"h-5 w-5 text-emerald-600 dark:text-emerald-400\" />\n </div>\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Security &amp; Recovery</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n A guardian can help you get back into this wallet if you ever lose this device.\n </p>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {inProgress && (\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription>\n A guardian has started replacing this wallet&apos;s owner key.{\" \"}\n {inProgress.status === \"Ready\"\n ? \"It can complete at any time.\"\n : `It can complete on ${new Date(inProgress.readyAt * 1000).toLocaleString()}.`}{\" \"}\n If this wasn&apos;t you, cancel it now.\n {cancelError && <p className=\"mt-1 text-destructive\">{cancelError}</p>}\n <Button\n onClick={handleCancel}\n disabled={cancelBusy}\n variant=\"destructive\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n >\n {cancelBusy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n Cancel recovery\n </Button>\n </AlertDescription>\n </Alert>\n )}\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 flex-wrap\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Guardian recovery</p>\n {status === null ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">Checking…</p>\n ) : status.kind === \"none\" ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {guardianRecoveryAvailable ? \"Not set up — add one from another device you trust.\" : \"Not available yet.\"}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Active: {status.guardian.type} guardian {short(status.guardian.storedValue)}\n </p>\n )}\n </div>\n {status?.kind === \"none\" && sealed && (\n <Button onClick={() => setAddOpen(true)} variant=\"outline\" size=\"sm\" disabled={!guardianRecoveryAvailable}>\n Add guardian\n </Button>\n )}\n {status?.kind === \"active\" && (\n <Badge variant=\"outline\" className=\"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 text-2xs\">\n Configured\n </Badge>\n )}\n </div>\n\n <Link\n href={recoverHref}\n className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 transition-colors hover:bg-foreground/[0.03]\"\n >\n <div>\n <p className=\"text-sm font-medium text-foreground\">Recover a wallet</p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Lost this device, or acting as someone&apos;s guardian?\n </p>\n </div>\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n </Link>\n </div>\n\n {sealed && guardianRecoveryAvailable && (\n <AddGuardianDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n sealed={sealed}\n onAdded={refresh}\n wallet={wallet}\n />\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyEU;AAvEV,mBAAiD;AACjD,0BAA2D;AAC3D,sBAKO;AACP,kBAAiB;AACjB,oBAAuB;AACvB,mBAAsB;AACtB,mBAAwC;AACxC,4BAA8B;AAC9B,iCAAkC;AAGlC,MAAM,QAAQ,CAAC,MAAc,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,SAAI,EAAE,MAAM,EAAE,CAAC;AAUrD,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAChB,GAAiC;AAC/B,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAgC,IAAI;AACtE,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAA4B,IAAI;AAC5D,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,IAAI;AAElE,QAAM,cAAU,0BAAY,MAAM;AAChC,WAAO,aAAa,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,MAAM,aAAa,CAAC,CAAC,CAAC;AAClF,WAAO,UAAU,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,MAAM,UAAU,IAAI,CAAC;AAAA,EAC7E,GAAG,CAAC,eAAe,MAAM,CAAC;AAE1B,8BAAU,MAAM;AAAE,YAAQ;AAAA,EAAG,GAAG,CAAC,OAAO,CAAC;AAEzC,QAAM,eAAe,YAAY;AAC/B,UAAMA,UAAS,WAAW;AAC1B,QAAI,CAACA,QAAQ;AACb,kBAAc,IAAI;AAClB,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,OAAO,aAAaA,OAAM;AAChC,cAAQ;AAAA,IACV,SAAS,GAAG;AACV,yBAAe,qCAAc,CAAC,EAAE,OAAO;AAAA,IACzC,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,QAAM,SAAS,gBAAY,wCAAuB,SAAS,IAAI;AAC/D,QAAM,iBAAiB,aAAS,wCAAuB,MAAM,IAAI;AACjE,QAAM,aAAa,QAAQ,eAAe,WAAW,mBAAmB,SAAS,SAAS;AAE1F,QAAM,SAAS,WAAW;AAE1B,SACE,6CAAC,SAAI,WAAU,oEACb;AAAA,iDAAC,SAAI,WAAU,0BACb;AAAA,kDAAC,SAAI,WAAU,sFACb,sDAAC,8BAAO,WAAU,kDAAiD,GACrE;AAAA,MACA,6CAAC,SACC;AAAA,oDAAC,QAAG,WAAU,uCAAsC,iCAAuB;AAAA,QAC3E,4CAAC,OAAE,WAAU,wCAAuC,6FAEpD;AAAA,SACF;AAAA,OACF;AAAA,IAEA,6CAAC,SAAI,WAAU,aACZ;AAAA,oBACC,6CAAC,sBAAM,SAAQ,eACb;AAAA,oDAAC,mCAAY,WAAU,WAAU;AAAA,QACjC,6CAAC,iCAAiB;AAAA;AAAA,UAC+C;AAAA,UAC9D,WAAW,WAAW,UACnB,iCACA,sBAAsB,IAAI,KAAK,WAAW,UAAU,GAAI,EAAE,eAAe,CAAC;AAAA,UAAK;AAAA,UAAI;AAAA,UAEtF,eAAe,4CAAC,OAAE,WAAU,yBAAyB,uBAAY;AAAA,UAClE;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,WAAU;AAAA,cAET;AAAA,6BAAa,4CAAC,+BAAQ,WAAU,mCAAkC,IAAK;AAAA,gBAAK;AAAA;AAAA;AAAA,UAE/E;AAAA,WACF;AAAA,SACF;AAAA,MAGF,6CAAC,SAAI,WAAU,4FACb;AAAA,qDAAC,SACC;AAAA,sDAAC,OAAE,WAAU,uCAAsC,+BAAiB;AAAA,UACnE,WAAW,OACV,4CAAC,OAAE,WAAU,wCAAuC,4BAAS,IAC3D,OAAO,SAAS,SAClB,4CAAC,OAAE,WAAU,wCACV,sCAA4B,6DAAwD,sBACvF,IAEA,6CAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,YACzC,OAAO,SAAS;AAAA,YAAK;AAAA,YAAW,MAAM,OAAO,SAAS,WAAW;AAAA,aAC5E;AAAA,WAEJ;AAAA,QACC,QAAQ,SAAS,UAAU,UAC1B,4CAAC,wBAAO,SAAS,MAAM,WAAW,IAAI,GAAG,SAAQ,WAAU,MAAK,MAAK,UAAU,CAAC,2BAA2B,0BAE3G;AAAA,QAED,QAAQ,SAAS,YAChB,4CAAC,sBAAM,SAAQ,WAAU,WAAU,2FAA0F,wBAE7H;AAAA,SAEJ;AAAA,MAEA;AAAA,QAAC,YAAAC;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,WAAU;AAAA,UAEV;AAAA,yDAAC,SACC;AAAA,0DAAC,OAAE,WAAU,uCAAsC,8BAAgB;AAAA,cACnE,4CAAC,OAAE,WAAU,wCAAuC,gEAEpD;AAAA,eACF;AAAA,YACA,4CAAC,oCAAa,WAAU,0CAAyC;AAAA;AAAA;AAAA,MACnE;AAAA,OACF;AAAA,IAEC,UAAU,6BACT;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,cAAc;AAAA,QACd;AAAA,QACA,SAAS;AAAA,QACT;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":["sealed","Link"]}
@@ -41,7 +41,7 @@ function GuardianRecoverySection({
41
41
  await wallet.cancelEscape(sealed2);
42
42
  refresh();
43
43
  } catch (e) {
44
- setCancelError(describeError(e, "We couldn't cancel recovery. Please try again.").message);
44
+ setCancelError(describeError(e).message);
45
45
  } finally {
46
46
  setCancelBusy(false);
47
47
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/account/guardian-recovery-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Shield, ShieldAlert, ChevronRight, Loader2 } from \"lucide-react\";\nimport {\n describeGuardianStatus,\n describeRecoveryAction,\n type EscapeInfo,\n type GuardianInfo,\n} from \"@medialane/sdk/starknet\";\nimport Link from \"../link.js\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { AddGuardianDialog } from \"./add-guardian-dialog.js\";\nimport type { GuardianWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (a: string) => `${a.slice(0, 6)}…${a.slice(-4)}`;\n\nexport interface GuardianRecoverySectionProps {\n walletAddress: string;\n wallet: GuardianWallet;\n loadSealed: LoadSealedOwner;\n guardianRecoveryAvailable: boolean;\n recoverHref?: string;\n}\n\nexport function GuardianRecoverySection({\n walletAddress,\n wallet,\n loadSealed,\n guardianRecoveryAvailable,\n recoverHref = \"/recover\",\n}: GuardianRecoverySectionProps) {\n const [guardians, setGuardians] = useState<GuardianInfo[] | null>(null);\n const [escape, setEscape] = useState<EscapeInfo | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [cancelBusy, setCancelBusy] = useState(false);\n const [cancelError, setCancelError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n wallet.getGuardians(walletAddress).then(setGuardians).catch(() => setGuardians([]));\n wallet.getEscape(walletAddress).then(setEscape).catch(() => setEscape(null));\n }, [walletAddress, wallet]);\n\n useEffect(() => { refresh(); }, [refresh]);\n\n const handleCancel = async () => {\n const sealed = loadSealed();\n if (!sealed) return;\n setCancelBusy(true);\n setCancelError(null);\n try {\n await wallet.cancelEscape(sealed);\n refresh();\n } catch (e) {\n setCancelError(describeError(e, \"We couldn't cancel recovery. Please try again.\").message);\n } finally {\n setCancelBusy(false);\n }\n };\n\n const status = guardians ? describeGuardianStatus(guardians) : null;\n const recoveryAction = escape ? describeRecoveryAction(escape) : \"none\";\n const inProgress = escape?.escapeType === \"Owner\" && recoveryAction !== \"none\" ? escape : null;\n\n const sealed = loadSealed();\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"h-10 w-10 shrink-0 rounded-full bg-emerald-500/10 flex items-center justify-center\">\n <Shield className=\"h-5 w-5 text-emerald-600 dark:text-emerald-400\" />\n </div>\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Security &amp; Recovery</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n A guardian can help you get back into this wallet if you ever lose this device.\n </p>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {inProgress && (\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription>\n A guardian has started replacing this wallet&apos;s owner key.{\" \"}\n {inProgress.status === \"Ready\"\n ? \"It can complete at any time.\"\n : `It can complete on ${new Date(inProgress.readyAt * 1000).toLocaleString()}.`}{\" \"}\n If this wasn&apos;t you, cancel it now.\n {cancelError && <p className=\"mt-1 text-destructive\">{cancelError}</p>}\n <Button\n onClick={handleCancel}\n disabled={cancelBusy}\n variant=\"destructive\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n >\n {cancelBusy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n Cancel recovery\n </Button>\n </AlertDescription>\n </Alert>\n )}\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 flex-wrap\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Guardian recovery</p>\n {status === null ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">Checking…</p>\n ) : status.kind === \"none\" ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {guardianRecoveryAvailable ? \"Not set up — add one from another device you trust.\" : \"Not available yet.\"}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Active: {status.guardian.type} guardian {short(status.guardian.storedValue)}\n </p>\n )}\n </div>\n {status?.kind === \"none\" && sealed && (\n <Button onClick={() => setAddOpen(true)} variant=\"outline\" size=\"sm\" disabled={!guardianRecoveryAvailable}>\n Add guardian\n </Button>\n )}\n {status?.kind === \"active\" && (\n <Badge variant=\"outline\" className=\"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 text-2xs\">\n Configured\n </Badge>\n )}\n </div>\n\n <Link\n href={recoverHref}\n className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 transition-colors hover:bg-foreground/[0.03]\"\n >\n <div>\n <p className=\"text-sm font-medium text-foreground\">Recover a wallet</p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Lost this device, or acting as someone&apos;s guardian?\n </p>\n </div>\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n </Link>\n </div>\n\n {sealed && guardianRecoveryAvailable && (\n <AddGuardianDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n sealed={sealed}\n onAdded={refresh}\n wallet={wallet}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["sealed"]}
1
+ {"version":3,"sources":["../../../src/components/account/guardian-recovery-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { Shield, ShieldAlert, ChevronRight, Loader2 } from \"lucide-react\";\nimport {\n describeGuardianStatus,\n describeRecoveryAction,\n type EscapeInfo,\n type GuardianInfo,\n} from \"@medialane/sdk/starknet\";\nimport Link from \"../link.js\";\nimport { Button } from \"../button.js\";\nimport { Badge } from \"../badge.js\";\nimport { Alert, AlertDescription } from \"../alert.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { AddGuardianDialog } from \"./add-guardian-dialog.js\";\nimport type { GuardianWallet, LoadSealedOwner } from \"./wallet-types.js\";\n\nconst short = (a: string) => `${a.slice(0, 6)}…${a.slice(-4)}`;\n\nexport interface GuardianRecoverySectionProps {\n walletAddress: string;\n wallet: GuardianWallet;\n loadSealed: LoadSealedOwner;\n guardianRecoveryAvailable: boolean;\n recoverHref?: string;\n}\n\nexport function GuardianRecoverySection({\n walletAddress,\n wallet,\n loadSealed,\n guardianRecoveryAvailable,\n recoverHref = \"/recover\",\n}: GuardianRecoverySectionProps) {\n const [guardians, setGuardians] = useState<GuardianInfo[] | null>(null);\n const [escape, setEscape] = useState<EscapeInfo | null>(null);\n const [addOpen, setAddOpen] = useState(false);\n const [cancelBusy, setCancelBusy] = useState(false);\n const [cancelError, setCancelError] = useState<string | null>(null);\n\n const refresh = useCallback(() => {\n wallet.getGuardians(walletAddress).then(setGuardians).catch(() => setGuardians([]));\n wallet.getEscape(walletAddress).then(setEscape).catch(() => setEscape(null));\n }, [walletAddress, wallet]);\n\n useEffect(() => { refresh(); }, [refresh]);\n\n const handleCancel = async () => {\n const sealed = loadSealed();\n if (!sealed) return;\n setCancelBusy(true);\n setCancelError(null);\n try {\n await wallet.cancelEscape(sealed);\n refresh();\n } catch (e) {\n setCancelError(describeError(e).message);\n } finally {\n setCancelBusy(false);\n }\n };\n\n const status = guardians ? describeGuardianStatus(guardians) : null;\n const recoveryAction = escape ? describeRecoveryAction(escape) : \"none\";\n const inProgress = escape?.escapeType === \"Owner\" && recoveryAction !== \"none\" ? escape : null;\n\n const sealed = loadSealed();\n\n return (\n <div className=\"rounded-2xl border border-border/60 bg-card p-5 sm:p-6 space-y-5\">\n <div className=\"flex items-start gap-3\">\n <div className=\"h-10 w-10 shrink-0 rounded-full bg-emerald-500/10 flex items-center justify-center\">\n <Shield className=\"h-5 w-5 text-emerald-600 dark:text-emerald-400\" />\n </div>\n <div>\n <h3 className=\"text-base font-bold text-foreground\">Security &amp; Recovery</h3>\n <p className=\"text-sm text-muted-foreground mt-0.5\">\n A guardian can help you get back into this wallet if you ever lose this device.\n </p>\n </div>\n </div>\n\n <div className=\"space-y-3\">\n {inProgress && (\n <Alert variant=\"destructive\">\n <ShieldAlert className=\"h-4 w-4\" />\n <AlertDescription>\n A guardian has started replacing this wallet&apos;s owner key.{\" \"}\n {inProgress.status === \"Ready\"\n ? \"It can complete at any time.\"\n : `It can complete on ${new Date(inProgress.readyAt * 1000).toLocaleString()}.`}{\" \"}\n If this wasn&apos;t you, cancel it now.\n {cancelError && <p className=\"mt-1 text-destructive\">{cancelError}</p>}\n <Button\n onClick={handleCancel}\n disabled={cancelBusy}\n variant=\"destructive\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n >\n {cancelBusy ? <Loader2 className=\"mr-1.5 h-3.5 w-3.5 animate-spin\" /> : null}\n Cancel recovery\n </Button>\n </AlertDescription>\n </Alert>\n )}\n\n <div className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 flex-wrap\">\n <div>\n <p className=\"text-sm font-medium text-foreground\">Guardian recovery</p>\n {status === null ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">Checking…</p>\n ) : status.kind === \"none\" ? (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {guardianRecoveryAvailable ? \"Not set up — add one from another device you trust.\" : \"Not available yet.\"}\n </p>\n ) : (\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Active: {status.guardian.type} guardian {short(status.guardian.storedValue)}\n </p>\n )}\n </div>\n {status?.kind === \"none\" && sealed && (\n <Button onClick={() => setAddOpen(true)} variant=\"outline\" size=\"sm\" disabled={!guardianRecoveryAvailable}>\n Add guardian\n </Button>\n )}\n {status?.kind === \"active\" && (\n <Badge variant=\"outline\" className=\"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 text-2xs\">\n Configured\n </Badge>\n )}\n </div>\n\n <Link\n href={recoverHref}\n className=\"flex items-center justify-between gap-3 rounded-xl border border-border/60 p-4 transition-colors hover:bg-foreground/[0.03]\"\n >\n <div>\n <p className=\"text-sm font-medium text-foreground\">Recover a wallet</p>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n Lost this device, or acting as someone&apos;s guardian?\n </p>\n </div>\n <ChevronRight className=\"h-4 w-4 text-muted-foreground shrink-0\" />\n </Link>\n </div>\n\n {sealed && guardianRecoveryAvailable && (\n <AddGuardianDialog\n open={addOpen}\n onOpenChange={setAddOpen}\n sealed={sealed}\n onAdded={refresh}\n wallet={wallet}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["sealed"]}
@@ -44,7 +44,7 @@ var import_reward_earned = require("./rewards/reward-earned.js");
44
44
  var import_skeleton = require("./skeleton.js");
45
45
  var import_textarea = require("./textarea.js");
46
46
  var import_transaction_dialog = require("./transaction-dialog.js");
47
- var import_transaction_done = require("./transaction-done.js");
47
+ var import_transaction_success = require("./transaction-success.js");
48
48
  var import_cn = require("../utils/cn.js");
49
49
  var import_explorer_url = require("../utils/explorer-url.js");
50
50
  var import_run_intent_calls = require("../utils/run-intent-calls.js");
@@ -286,13 +286,14 @@ function CommentsSection({ contract, tokenId, className }) {
286
286
  }
287
287
  ),
288
288
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_transaction_dialog.TransactionDialog, { tx, title: "Comment", workingLabel: "Posting your comment\u2026", firstStepLabel: "Prepare comment", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
289
- import_transaction_done.TransactionDone,
289
+ import_transaction_success.TransactionSuccess,
290
290
  {
291
- tx,
292
291
  name: "Comment",
293
292
  title: "Comment posted!",
294
293
  description: "Your comment is onchain and will appear here once indexed (~30s).",
295
- footer: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_reward_earned.RewardEarned, { actionType: "comment" })
294
+ txHash: tx.txHash,
295
+ actions: [{ label: "Done", onClick: tx.reset }],
296
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_reward_earned.RewardEarned, { actionType: "comment" })
296
297
  }
297
298
  ) })
298
299
  ] });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/comments-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { ExternalLink, Flag, Loader2, MessageCircle, Send, Zap } from \"lucide-react\";\nimport { normalizeAddress, profileHref, STARKNET_NFTCOMMENTS_CONTRACT } from \"@medialane/sdk\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { Button } from \"./button.js\";\nimport Link from \"./link.js\";\nimport { useMedialaneApp, type ReportTarget } from \"./medialane-app.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionDone } from \"./transaction-done.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nconst MAX_LEN = 1000;\n\nexport interface CommentsSectionProps {\n contract: string;\n tokenId: string;\n className?: string;\n}\n\nexport function CommentsSection({ contract, tokenId, className }: CommentsSectionProps) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const hasWallet = !!walletAddress;\n const { ReportDialog } = app;\n const { comments, isLoading, mutate } = useComments(contract, tokenId);\n const tx = useTransaction();\n\n const [text, setText] = useState(\"\");\n const [reportTarget, setReportTarget] = useState<ReportTarget | null>(null);\n\n const messagesRef = useRef<HTMLDivElement>(null);\n const bottomRef = useRef<HTMLDivElement>(null);\n const composeRef = useRef<HTMLTextAreaElement>(null);\n\n const byteLen = new TextEncoder().encode(text).length;\n const canSubmit = text.trim().length > 0 && byteLen <= MAX_LEN && !!STARKNET_NFTCOMMENTS_CONTRACT;\n const isProcessing = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n const isOwn = (author: string) =>\n !!walletAddress && normalizeAddress(\"STARKNET\", author) === normalizeAddress(\"STARKNET\", walletAddress);\n\n const isNearBottom = () => {\n const el = messagesRef.current;\n if (!el) return true;\n return el.scrollHeight - el.scrollTop - el.clientHeight < 100;\n };\n\n useEffect(() => {\n if (isNearBottom()) {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }\n\n }, [comments.length]);\n\n const handleTextInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value);\n e.target.style.height = \"auto\";\n e.target.style.height = Math.min(e.target.scrollHeight, 96) + \"px\";\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey && canSubmit && !isProcessing) {\n e.preventDefault();\n post();\n }\n };\n\n const post = () => {\n const body = text.trim();\n void tx\n .run(async (signer) => {\n await runIntentCalls(signer, () =>\n app.getClient().api.intents.create(\"comment\", { author: signer.address, nftContract: contract, tokenId, text: body }),\n );\n })\n .then((ok) => {\n if (!ok) return;\n setText(\"\");\n if (composeRef.current) composeRef.current.style.height = \"auto\";\n void mutate();\n });\n };\n\n const handleStartConversation = () => {\n if (hasWallet) composeRef.current?.focus();\n };\n\n return (\n <div className={cn(\"flex flex-col h-[480px] overflow-hidden\", className)}>\n\n <div ref={messagesRef} className=\"flex-1 overflow-y-auto px-4 py-4\">\n {isLoading ? (\n <div className=\"space-y-4\">\n {([\n { own: false, w: \"w-40\" },\n { own: true, w: \"w-56\" },\n { own: false, w: \"w-48\" },\n { own: true, w: \"w-32\" },\n ] as const).map((item, i) => (\n <div key={i} className={`flex ${item.own ? \"justify-end\" : \"justify-start\"} gap-2`}>\n {!item.own && <Skeleton className=\"h-8 w-8 rounded-full shrink-0\" />}\n <Skeleton\n className={`h-10 ${item.w} rounded-2xl ${item.own ? \"rounded-tr-sm\" : \"rounded-tl-sm\"}`}\n />\n </div>\n ))}\n </div>\n ) : comments.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-full gap-4 text-center px-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full\" style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue) / 0.15), hsl(var(--brand-purple) / 0.15))\" }}>\n <MessageCircle className=\"h-7 w-7\" style={{ color: \"hsl(var(--brand-blue))\" }} />\n </div>\n <div>\n <p className=\"text-sm font-semibold\">Nothing here yet</p>\n <p className=\"text-xs text-muted-foreground mt-1 leading-relaxed max-w-[220px]\">\n Your comment will be minted onchain — attached to this NFT forever.\n </p>\n </div>\n <Button\n size=\"sm\"\n onClick={handleStartConversation}\n className=\"rounded-full text-white px-5\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n Write the first comment\n </Button>\n </div>\n ) : (\n <div className=\"space-y-5\">\n {comments.map((comment) => {\n const own = isOwn(comment.author);\n const avatarSeed = parseInt(comment.author.slice(2, 8), 16) % 360;\n const avatarBg = own\n ? \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\"\n : `linear-gradient(135deg, hsl(${avatarSeed}, 65%, 45%), hsl(${(avatarSeed + 60) % 360}, 65%, 55%))`;\n\n return (\n <div\n key={comment.id}\n className={`group flex gap-2.5 ${own ? \"flex-row-reverse\" : \"flex-row\"}`}\n >\n\n <Link href={profileHref({ address: comment.author })} className=\"shrink-0 mt-0.5\">\n <div\n className=\"h-9 w-9 rounded-full flex items-center justify-center text-2xs font-bold text-white select-none ring-2 ring-background hover:ring-primary/40 transition-all\"\n style={{ background: avatarBg }}\n >\n {comment.author.slice(2, 5).toUpperCase()}\n </div>\n </Link>\n\n <div className={`flex flex-col max-w-[75%] gap-1 ${own ? \"items-end\" : \"items-start\"}`}>\n\n <div className={`flex items-center gap-2 px-1 ${own ? \"flex-row-reverse\" : \"flex-row\"}`}>\n <Link\n href={profileHref({ address: comment.author })}\n className=\"text-xs font-semibold text-foreground hover:underline underline-offset-2\"\n >\n {own ? \"You\" : <AddressDisplay address={comment.author} chars={5} showCopy={false} />}\n </Link>\n <span className=\"text-2xs text-muted-foreground\" title={comment.postedAt}>\n {timeAgo(comment.postedAt)}\n </span>\n </div>\n\n <div className=\"relative\">\n {own ? (\n <div\n className=\"px-3.5 py-2.5 text-sm leading-relaxed break-words rounded-2xl rounded-tr-sm text-white\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n {comment.content}\n </div>\n ) : (\n <div className=\"px-3.5 py-2.5 text-sm leading-relaxed break-words bg-muted rounded-2xl rounded-tl-sm border border-border/50\">\n {comment.content}\n </div>\n )}\n {!own && hasWallet && (\n <button\n className=\"absolute -top-1 -right-5 opacity-0 group-hover:opacity-100 transition-opacity text-muted-foreground/40 hover:text-destructive/70\"\n title=\"Report comment\"\n aria-label=\"Report comment\"\n onClick={() => setReportTarget({ type: \"COMMENT\", commentId: comment.id })}\n >\n <Flag className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n\n {comment.txHash && (\n <a\n href={`${EXPLORER_URL}/tx/${comment.txHash}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 px-1 text-2xs font-medium transition-colors\"\n style={{ color: \"hsl(var(--brand-blue) / 0.55)\" }}\n onMouseEnter={(e) => (e.currentTarget.style.color = \"hsl(var(--brand-blue))\")}\n onMouseLeave={(e) => (e.currentTarget.style.color = \"hsl(var(--brand-blue) / 0.55)\")}\n >\n <span>⛓</span>\n <span>onchain proof</span>\n <ExternalLink className=\"h-2.5 w-2.5\" />\n </a>\n )}\n </div>\n </div>\n );\n })}\n <div ref={bottomRef} />\n </div>\n )}\n </div>\n\n <div className=\"border-t border-border/60 shrink-0\">\n {!hasWallet ? (\n <div className=\"flex items-center justify-center px-4 h-16\">\n <button type=\"button\" onClick={app.onRequireWallet} className=\"text-sm text-primary hover:underline\">\n {app.connectLabel ?? \"Connect\"} to comment\n </button>\n </div>\n ) : (\n <div className=\"px-3 pt-2 pb-3 space-y-2\">\n\n <div className=\"flex items-center gap-1.5\">\n <Zap className=\"h-3 w-3\" style={{ color: \"hsl(var(--brand-blue))\" }} />\n <span className=\"text-2xs font-semibold\" style={{ color: \"hsl(var(--brand-blue))\" }}>\n Mint your message onchain\n </span>\n </div>\n\n <div\n className=\"rounded-xl border bg-background/60 transition-all focus-within:ring-2\"\n style={{\n borderColor: \"hsl(var(--border))\",\n }}\n onFocusCapture={(e) => {\n (e.currentTarget as HTMLDivElement).style.borderColor = \"hsl(var(--brand-blue) / 0.6)\";\n (e.currentTarget as HTMLDivElement).style.boxShadow = \"0 0 0 3px hsl(var(--brand-blue) / 0.12)\";\n }}\n onBlurCapture={(e) => {\n (e.currentTarget as HTMLDivElement).style.borderColor = \"hsl(var(--border))\";\n (e.currentTarget as HTMLDivElement).style.boxShadow = \"\";\n }}\n >\n <Textarea\n ref={composeRef}\n placeholder=\"Say something onchain… it's permanent.\"\n value={text}\n onChange={handleTextInput}\n onKeyDown={handleKeyDown}\n rows={2}\n className=\"resize-none min-h-[52px] max-h-[120px] w-full border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-3 pt-2.5 pb-1 text-sm rounded-xl\"\n disabled={isProcessing}\n />\n <div className=\"flex items-center justify-between px-3 pb-2.5\">\n <span className=\"text-2xs text-muted-foreground/40 flex items-center gap-1\">\n Enter ↵ to post\n </span>\n <div className=\"flex items-center gap-2\">\n {byteLen > 800 && (\n <span className={`text-2xs ${byteLen > MAX_LEN ? \"text-destructive\" : \"text-muted-foreground\"}`}>\n {byteLen}/{MAX_LEN}\n </span>\n )}\n <button\n onClick={post}\n disabled={!canSubmit || isProcessing}\n className=\"flex items-center gap-1.5 h-7 px-3 text-xs font-semibold rounded-full text-white transition-all hover:opacity-90 active:scale-95 disabled:opacity-40 disabled:cursor-not-allowed\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n {isProcessing ? <Loader2 className=\"h-3 w-3 animate-spin\" /> : <Send className=\"h-3 w-3\" />}\n Post onchain\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n\n {reportTarget && ReportDialog && (\n <ReportDialog\n target={reportTarget}\n open={!!reportTarget}\n onOpenChange={(open) => { if (!open) setReportTarget(null); }}\n />\n )}\n\n <TransactionDialog tx={tx} title=\"Comment\" workingLabel=\"Posting your comment…\" firstStepLabel=\"Prepare comment\">\n <TransactionDone\n tx={tx}\n name=\"Comment\"\n title=\"Comment posted!\"\n description=\"Your comment is onchain and will appear here once indexed (~30s).\"\n footer={<RewardEarned actionType=\"comment\" />}\n />\n </TransactionDialog>\n </div>\n );\n}\n"],"mappings":"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","names":["Link"]}
1
+ {"version":3,"sources":["../../src/components/comments-section.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { ExternalLink, Flag, Loader2, MessageCircle, Send, Zap } from \"lucide-react\";\nimport { normalizeAddress, profileHref, STARKNET_NFTCOMMENTS_CONTRACT } from \"@medialane/sdk\";\nimport { AddressDisplay } from \"./address-display.js\";\nimport { Button } from \"./button.js\";\nimport Link from \"./link.js\";\nimport { useMedialaneApp, type ReportTarget } from \"./medialane-app.js\";\nimport { RewardEarned } from \"./rewards/reward-earned.js\";\nimport { Skeleton } from \"./skeleton.js\";\nimport { Textarea } from \"./textarea.js\";\nimport { TransactionDialog } from \"./transaction-dialog.js\";\nimport { TransactionSuccess } from \"./transaction-success.js\";\nimport { cn } from \"../utils/cn.js\";\nimport { EXPLORER_URL } from \"../utils/explorer-url.js\";\nimport { runIntentCalls } from \"../utils/run-intent-calls.js\";\nimport { timeAgo } from \"../utils/time.js\";\nimport { useComments } from \"../utils/use-comments.js\";\nimport { useTransaction } from \"../utils/use-transaction.js\";\n\nconst MAX_LEN = 1000;\n\nexport interface CommentsSectionProps {\n contract: string;\n tokenId: string;\n className?: string;\n}\n\nexport function CommentsSection({ contract, tokenId, className }: CommentsSectionProps) {\n const app = useMedialaneApp();\n const walletAddress = app.walletAddress;\n const hasWallet = !!walletAddress;\n const { ReportDialog } = app;\n const { comments, isLoading, mutate } = useComments(contract, tokenId);\n const tx = useTransaction();\n\n const [text, setText] = useState(\"\");\n const [reportTarget, setReportTarget] = useState<ReportTarget | null>(null);\n\n const messagesRef = useRef<HTMLDivElement>(null);\n const bottomRef = useRef<HTMLDivElement>(null);\n const composeRef = useRef<HTMLTextAreaElement>(null);\n\n const byteLen = new TextEncoder().encode(text).length;\n const canSubmit = text.trim().length > 0 && byteLen <= MAX_LEN && !!STARKNET_NFTCOMMENTS_CONTRACT;\n const isProcessing = tx.phase === \"preparing\" || tx.phase === \"submitting\" || tx.phase === \"confirming\";\n\n const isOwn = (author: string) =>\n !!walletAddress && normalizeAddress(\"STARKNET\", author) === normalizeAddress(\"STARKNET\", walletAddress);\n\n const isNearBottom = () => {\n const el = messagesRef.current;\n if (!el) return true;\n return el.scrollHeight - el.scrollTop - el.clientHeight < 100;\n };\n\n useEffect(() => {\n if (isNearBottom()) {\n bottomRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }\n\n }, [comments.length]);\n\n const handleTextInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n setText(e.target.value);\n e.target.style.height = \"auto\";\n e.target.style.height = Math.min(e.target.scrollHeight, 96) + \"px\";\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === \"Enter\" && !e.shiftKey && canSubmit && !isProcessing) {\n e.preventDefault();\n post();\n }\n };\n\n const post = () => {\n const body = text.trim();\n void tx\n .run(async (signer) => {\n await runIntentCalls(signer, () =>\n app.getClient().api.intents.create(\"comment\", { author: signer.address, nftContract: contract, tokenId, text: body }),\n );\n })\n .then((ok) => {\n if (!ok) return;\n setText(\"\");\n if (composeRef.current) composeRef.current.style.height = \"auto\";\n void mutate();\n });\n };\n\n const handleStartConversation = () => {\n if (hasWallet) composeRef.current?.focus();\n };\n\n return (\n <div className={cn(\"flex flex-col h-[480px] overflow-hidden\", className)}>\n\n <div ref={messagesRef} className=\"flex-1 overflow-y-auto px-4 py-4\">\n {isLoading ? (\n <div className=\"space-y-4\">\n {([\n { own: false, w: \"w-40\" },\n { own: true, w: \"w-56\" },\n { own: false, w: \"w-48\" },\n { own: true, w: \"w-32\" },\n ] as const).map((item, i) => (\n <div key={i} className={`flex ${item.own ? \"justify-end\" : \"justify-start\"} gap-2`}>\n {!item.own && <Skeleton className=\"h-8 w-8 rounded-full shrink-0\" />}\n <Skeleton\n className={`h-10 ${item.w} rounded-2xl ${item.own ? \"rounded-tr-sm\" : \"rounded-tl-sm\"}`}\n />\n </div>\n ))}\n </div>\n ) : comments.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center h-full gap-4 text-center px-4\">\n <div className=\"flex h-16 w-16 items-center justify-center rounded-full\" style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue) / 0.15), hsl(var(--brand-purple) / 0.15))\" }}>\n <MessageCircle className=\"h-7 w-7\" style={{ color: \"hsl(var(--brand-blue))\" }} />\n </div>\n <div>\n <p className=\"text-sm font-semibold\">Nothing here yet</p>\n <p className=\"text-xs text-muted-foreground mt-1 leading-relaxed max-w-[220px]\">\n Your comment will be minted onchain — attached to this NFT forever.\n </p>\n </div>\n <Button\n size=\"sm\"\n onClick={handleStartConversation}\n className=\"rounded-full text-white px-5\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n Write the first comment\n </Button>\n </div>\n ) : (\n <div className=\"space-y-5\">\n {comments.map((comment) => {\n const own = isOwn(comment.author);\n const avatarSeed = parseInt(comment.author.slice(2, 8), 16) % 360;\n const avatarBg = own\n ? \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\"\n : `linear-gradient(135deg, hsl(${avatarSeed}, 65%, 45%), hsl(${(avatarSeed + 60) % 360}, 65%, 55%))`;\n\n return (\n <div\n key={comment.id}\n className={`group flex gap-2.5 ${own ? \"flex-row-reverse\" : \"flex-row\"}`}\n >\n\n <Link href={profileHref({ address: comment.author })} className=\"shrink-0 mt-0.5\">\n <div\n className=\"h-9 w-9 rounded-full flex items-center justify-center text-2xs font-bold text-white select-none ring-2 ring-background hover:ring-primary/40 transition-all\"\n style={{ background: avatarBg }}\n >\n {comment.author.slice(2, 5).toUpperCase()}\n </div>\n </Link>\n\n <div className={`flex flex-col max-w-[75%] gap-1 ${own ? \"items-end\" : \"items-start\"}`}>\n\n <div className={`flex items-center gap-2 px-1 ${own ? \"flex-row-reverse\" : \"flex-row\"}`}>\n <Link\n href={profileHref({ address: comment.author })}\n className=\"text-xs font-semibold text-foreground hover:underline underline-offset-2\"\n >\n {own ? \"You\" : <AddressDisplay address={comment.author} chars={5} showCopy={false} />}\n </Link>\n <span className=\"text-2xs text-muted-foreground\" title={comment.postedAt}>\n {timeAgo(comment.postedAt)}\n </span>\n </div>\n\n <div className=\"relative\">\n {own ? (\n <div\n className=\"px-3.5 py-2.5 text-sm leading-relaxed break-words rounded-2xl rounded-tr-sm text-white\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n {comment.content}\n </div>\n ) : (\n <div className=\"px-3.5 py-2.5 text-sm leading-relaxed break-words bg-muted rounded-2xl rounded-tl-sm border border-border/50\">\n {comment.content}\n </div>\n )}\n {!own && hasWallet && (\n <button\n className=\"absolute -top-1 -right-5 opacity-0 group-hover:opacity-100 transition-opacity text-muted-foreground/40 hover:text-destructive/70\"\n title=\"Report comment\"\n aria-label=\"Report comment\"\n onClick={() => setReportTarget({ type: \"COMMENT\", commentId: comment.id })}\n >\n <Flag className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n\n {comment.txHash && (\n <a\n href={`${EXPLORER_URL}/tx/${comment.txHash}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"flex items-center gap-1 px-1 text-2xs font-medium transition-colors\"\n style={{ color: \"hsl(var(--brand-blue) / 0.55)\" }}\n onMouseEnter={(e) => (e.currentTarget.style.color = \"hsl(var(--brand-blue))\")}\n onMouseLeave={(e) => (e.currentTarget.style.color = \"hsl(var(--brand-blue) / 0.55)\")}\n >\n <span>⛓</span>\n <span>onchain proof</span>\n <ExternalLink className=\"h-2.5 w-2.5\" />\n </a>\n )}\n </div>\n </div>\n );\n })}\n <div ref={bottomRef} />\n </div>\n )}\n </div>\n\n <div className=\"border-t border-border/60 shrink-0\">\n {!hasWallet ? (\n <div className=\"flex items-center justify-center px-4 h-16\">\n <button type=\"button\" onClick={app.onRequireWallet} className=\"text-sm text-primary hover:underline\">\n {app.connectLabel ?? \"Connect\"} to comment\n </button>\n </div>\n ) : (\n <div className=\"px-3 pt-2 pb-3 space-y-2\">\n\n <div className=\"flex items-center gap-1.5\">\n <Zap className=\"h-3 w-3\" style={{ color: \"hsl(var(--brand-blue))\" }} />\n <span className=\"text-2xs font-semibold\" style={{ color: \"hsl(var(--brand-blue))\" }}>\n Mint your message onchain\n </span>\n </div>\n\n <div\n className=\"rounded-xl border bg-background/60 transition-all focus-within:ring-2\"\n style={{\n borderColor: \"hsl(var(--border))\",\n }}\n onFocusCapture={(e) => {\n (e.currentTarget as HTMLDivElement).style.borderColor = \"hsl(var(--brand-blue) / 0.6)\";\n (e.currentTarget as HTMLDivElement).style.boxShadow = \"0 0 0 3px hsl(var(--brand-blue) / 0.12)\";\n }}\n onBlurCapture={(e) => {\n (e.currentTarget as HTMLDivElement).style.borderColor = \"hsl(var(--border))\";\n (e.currentTarget as HTMLDivElement).style.boxShadow = \"\";\n }}\n >\n <Textarea\n ref={composeRef}\n placeholder=\"Say something onchain… it's permanent.\"\n value={text}\n onChange={handleTextInput}\n onKeyDown={handleKeyDown}\n rows={2}\n className=\"resize-none min-h-[52px] max-h-[120px] w-full border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 px-3 pt-2.5 pb-1 text-sm rounded-xl\"\n disabled={isProcessing}\n />\n <div className=\"flex items-center justify-between px-3 pb-2.5\">\n <span className=\"text-2xs text-muted-foreground/40 flex items-center gap-1\">\n Enter ↵ to post\n </span>\n <div className=\"flex items-center gap-2\">\n {byteLen > 800 && (\n <span className={`text-2xs ${byteLen > MAX_LEN ? \"text-destructive\" : \"text-muted-foreground\"}`}>\n {byteLen}/{MAX_LEN}\n </span>\n )}\n <button\n onClick={post}\n disabled={!canSubmit || isProcessing}\n className=\"flex items-center gap-1.5 h-7 px-3 text-xs font-semibold rounded-full text-white transition-all hover:opacity-90 active:scale-95 disabled:opacity-40 disabled:cursor-not-allowed\"\n style={{ background: \"linear-gradient(135deg, hsl(var(--brand-blue)), hsl(var(--brand-purple)))\" }}\n >\n {isProcessing ? <Loader2 className=\"h-3 w-3 animate-spin\" /> : <Send className=\"h-3 w-3\" />}\n Post onchain\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </div>\n\n {reportTarget && ReportDialog && (\n <ReportDialog\n target={reportTarget}\n open={!!reportTarget}\n onOpenChange={(open) => { if (!open) setReportTarget(null); }}\n />\n )}\n\n <TransactionDialog tx={tx} title=\"Comment\" workingLabel=\"Posting your comment…\" firstStepLabel=\"Prepare comment\">\n <TransactionSuccess\n name=\"Comment\"\n title=\"Comment posted!\"\n description=\"Your comment is onchain and will appear here once indexed (~30s).\"\n txHash={tx.txHash}\n actions={[{ label: \"Done\", onClick: tx.reset }]}\n >\n <RewardEarned actionType=\"comment\" />\n </TransactionSuccess>\n </TransactionDialog>\n </div>\n );\n}\n"],"mappings":"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","names":["Link"]}
@@ -11,7 +11,7 @@ import { RewardEarned } from "./rewards/reward-earned.js";
11
11
  import { Skeleton } from "./skeleton.js";
12
12
  import { Textarea } from "./textarea.js";
13
13
  import { TransactionDialog } from "./transaction-dialog.js";
14
- import { TransactionDone } from "./transaction-done.js";
14
+ import { TransactionSuccess } from "./transaction-success.js";
15
15
  import { cn } from "../utils/cn.js";
16
16
  import { EXPLORER_URL } from "../utils/explorer-url.js";
17
17
  import { runIntentCalls } from "../utils/run-intent-calls.js";
@@ -253,13 +253,14 @@ function CommentsSection({ contract, tokenId, className }) {
253
253
  }
254
254
  ),
255
255
  /* @__PURE__ */ jsx(TransactionDialog, { tx, title: "Comment", workingLabel: "Posting your comment\u2026", firstStepLabel: "Prepare comment", children: /* @__PURE__ */ jsx(
256
- TransactionDone,
256
+ TransactionSuccess,
257
257
  {
258
- tx,
259
258
  name: "Comment",
260
259
  title: "Comment posted!",
261
260
  description: "Your comment is onchain and will appear here once indexed (~30s).",
262
- footer: /* @__PURE__ */ jsx(RewardEarned, { actionType: "comment" })
261
+ txHash: tx.txHash,
262
+ actions: [{ label: "Done", onClick: tx.reset }],
263
+ children: /* @__PURE__ */ jsx(RewardEarned, { actionType: "comment" })
263
264
  }
264
265
  ) })
265
266
  ] });